git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9508 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
Giovanni Di Sirio 2016-05-24 13:57:49 +00:00
parent b36f9f5585
commit a3c37f98cc
6 changed files with 229 additions and 33 deletions

View File

@ -25,8 +25,9 @@
* @{
*/
#include "hal.h"
#include <string.h>
#include "hal.h"
#include "m25q.h"
/*===========================================================================*/
@ -82,11 +83,7 @@ static flash_descriptor_t descriptor = {
.attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |
FLASH_ATTR_SUSPEND_ERASE_CAPABLE,
.page_size = 256U,
#if M25Q_USE_SUB_SECTORS == TRUE
.sectors_count = 4096U,
#else
.sectors_count = 256U,
#endif
.sectors_count = 0U, /* It is overwritten.*/
.sectors = NULL,
.sectors_size = SECTOR_SIZE,
.address = 0U
@ -209,9 +206,11 @@ static const uint8_t evconf_value[1] = {0xCF};
#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L
static const uint8_t evconf_value[1] = {0x8F};
#else
static const uint8_t evconf_value[1] = {0xCF};//{0x4F};
static const uint8_t evconf_value[1] = {0x4F};
#endif
static const uint8_t flash_status[1] = {(M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU};
#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */
/*===========================================================================*/
@ -314,6 +313,39 @@ static void flash_cmd_receive(M25QDriver *devp,
#endif
}
static void flash_cmd_send(M25QDriver *devp,
uint8_t cmd,
size_t n,
const uint8_t *p) {
#if M25Q_BUS_MODE != M25Q_BUS_MODE_SPI
qspi_command_t mode;
mode.cfg = QSPI_CFG_CMD(cmd) |
#if M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI1L
QSPI_CFG_CMD_MODE_ONE_LINE |
QSPI_CFG_DATA_MODE_ONE_LINE;
#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L
QSPI_CFG_CMD_MODE_TWO_LINES |
QSPI_CFG_DATA_MODE_TWO_LINES;
#else
QSPI_CFG_CMD_MODE_FOUR_LINES |
QSPI_CFG_DATA_MODE_FOUR_LINES;
#endif
mode.addr = 0U;
mode.alt = 0U;
qspiSend(devp->config->qspip, &mode, n, p);
#else
uint8_t buf[1];
spiSelect(devp->config->spip);
buf[0] = cmd;
spiSend(devp->config->spip, 1, buf);
spiSend(devp->config->spip, n, p);
spiUnselect(devp->config->spip);
#endif
}
static void flash_cmd_addr(M25QDriver *devp,
uint8_t cmd,
flash_address_t addr) {
@ -437,6 +469,42 @@ static void flash_cmd_addr_receive(M25QDriver *devp,
#endif
}
#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) || defined(__DOXYGEN__)
static void flash_cmd_addr_dummy_receive(M25QDriver *devp,
uint8_t cmd,
flash_address_t addr,
uint8_t dummy,
size_t n,
uint8_t *p) {
qspi_command_t mode;
mode.cfg = QSPI_CFG_CMD(cmd) |
#if M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI1L
QSPI_CFG_CMD_MODE_ONE_LINE |
QSPI_CFG_ADDR_MODE_ONE_LINE |
QSPI_CFG_ADDR_SIZE_24 |
QSPI_CFG_DUMMY_CYCLES(dummy) |
QSPI_CFG_DATA_MODE_ONE_LINE;
#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L
QSPI_CFG_CMD_MODE_TWO_LINES |
QSPI_CFG_ADDR_MODE_TWO_LINES |
QSPI_CFG_ADDR_SIZE_24 |
QSPI_CFG_DUMMY_CYCLES(dummy) |
QSPI_CFG_DATA_MODE_TWO_LINES;
#else
QSPI_CFG_CMD_MODE_FOUR_LINES |
QSPI_CFG_ADDR_MODE_FOUR_LINES |
QSPI_CFG_ADDR_SIZE_24 |
QSPI_CFG_DUMMY_CYCLES(dummy) |
QSPI_CFG_DATA_MODE_FOUR_LINES;
#endif
mode.addr = addr;
mode.alt = 0U;
qspiReceive(devp->config->qspip, &mode, n, p);
}
#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */
static flash_error_t flash_poll_status(M25QDriver *devp) {
return FLASH_NO_ERROR;
@ -454,6 +522,38 @@ static const flash_descriptor_t *get_descriptor(void *instance) {
static flash_error_t read(void *instance, flash_address_t addr,
uint8_t *rp, size_t n) {
M25QDriver *devp = (M25QDriver *)instance;
osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
osalDbgCheck((size_t)addr + n <= (size_t)descriptor.sectors_count *
(size_t)descriptor.sectors_size);
osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
"invalid state");
if (devp->state == FLASH_ERASE) {
return FLASH_BUSY_ERASING;
}
/* Bus acquired.*/
flash_bus_acquire(devp);
/* FLASH_READY state while the operation is performed.*/
devp->state = FLASH_READ;
#if M25Q_BUS_MODE != M25Q_BUS_MODE_SPI
/* Fast read command in QSPI mode.*/
flash_cmd_addr_dummy_receive(devp, M25Q_CMD_FAST_READ,
addr, M25Q_READ_DUMMY_CYCLES,
n, rp);
#else
/* Normal read command in SPI mode.*/
#endif
/* Ready state again.*/
devp->state = FLASH_READY;
/* Bus released.*/
flash_bus_release(devp);
return FLASH_NO_ERROR;
}
@ -516,6 +616,18 @@ void m25qObjectInit(M25QDriver *devp) {
#endif
}
static const qspi_command_t cmd_test_reset_enable_4 = {
.cfg = QSPI_CFG_ALT_MODE_FOUR_LINES,
.addr = 0,
.alt = M25Q_CMD_RESET_ENABLE
};
static const qspi_command_t cmd_test_reset_memory_4 = {
.cfg = QSPI_CFG_ALT_MODE_FOUR_LINES,
.addr = 0,
.alt = M25Q_CMD_RESET_MEMORY
};
/**
* @brief Configures and activates N25Q128 driver.
*
@ -532,7 +644,6 @@ void m25qStart(M25QDriver *devp, const M25QConfig *config) {
devp->config = config;
if (devp->state == FLASH_STOP) {
uint8_t id[3];
/* Bus acquisition.*/
flash_bus_acquire(devp);
@ -546,46 +657,62 @@ void m25qStart(M25QDriver *devp, const M25QConfig *config) {
/* QSPI initialization.*/
qspiStart(devp->config->qspip, devp->config->qspicfg);
/* Reading device ID and unique ID.*/
#if M25Q_SWITCH_WIDTH == TRUE
/* Attempting a device reset with decreasing bus widths, commands
/* Attempting a device reset with different bus widths, commands
shorter than 8 bits are ignored.*/
qspiCommand(devp->config->qspip, &cmd_reset_enable_4);
qspiCommand(devp->config->qspip, &cmd_reset_memory_4);
qspiCommand(devp->config->qspip, &cmd_reset_enable_2);
qspiCommand(devp->config->qspip, &cmd_reset_memory_2);
qspiCommand(devp->config->qspip, &cmd_reset_enable_1);
qspiCommand(devp->config->qspip, &cmd_reset_memory_1);
qspiCommand(devp->config->qspip, &cmd_reset_enable_2);
qspiCommand(devp->config->qspip, &cmd_reset_memory_2);
qspiCommand(devp->config->qspip, &cmd_reset_enable_4);
qspiCommand(devp->config->qspip, &cmd_reset_memory_4);
#endif
/* Reading device ID.*/
qspiReceive(devp->config->qspip, &cmd_read_id, 3, id);
/* Reading device ID and unique ID.*/
qspiReceive(devp->config->qspip, &cmd_read_id,
sizeof devp->device_id, devp->device_id);
#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */
/* Checking if the device is white listed.*/
osalDbgAssert(find_id(manufacturer_ids, sizeof manufacturer_ids, id[0]),
osalDbgAssert(find_id(manufacturer_ids,
sizeof manufacturer_ids,
devp->device_id[0]),
"invalid manufacturer id");
osalDbgAssert(find_id(memory_type_ids, sizeof memory_type_ids, id[1]),
osalDbgAssert(find_id(memory_type_ids,
sizeof memory_type_ids,
devp->device_id[1]),
"invalid memory type id");
#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)
/* Setting up final bus width.*/
qspiCommand(devp->config->qspip, &cmd_write_enable);
qspiSend(devp->config->qspip, &cmd_write_evconf, 1, evconf_value);
{
uint8_t id[3];
/* Reading ID again for confirmation.*/
flash_cmd_receive(devp, M25Q_CMD_MULTIPLE_IO_READ_ID, 3, id);
/* Checking if the device is white listed.*/
osalDbgAssert(memcmp(id, devp->device_id, 3) == 0,
"id confirmation failed");
}
#endif
flash_cmd_receive(devp, M25Q_CMD_READ_ID, 3, id);
/* Setting up the device size.*/
descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) / SECTOR_SIZE;
flash_cmd_receive(devp, M25Q_CMD_READ_ID, 3, id);
/* Reading device ID.*/
qspiReceive(devp->config->qspip, &cmd_read_id, 3, id);
/* Reset Enable command.*/
// flash_short_cmd(devp, M25Q_CMD_RESET_ENABLE);
/* Reset Memory command.*/
// flash_short_cmd(devp, M25Q_CMD_RESET_MEMORY);
#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI)
/* Setting up the dummy cycles to be used for rast read operations.*/
flash_cmd(devp, M25Q_CMD_WRITE_ENABLE);
flash_cmd_send(devp, M25Q_CMD_WRITE_V_CONF_REGISTER,
1, flash_status);
#endif
/* Driver in ready state.*/
devp->state = FLASH_READY;
/* Bus release.*/
@ -617,6 +744,8 @@ void m25qStop(M25QDriver *devp) {
#endif
devp->config = NULL;
/* Driver stopped.*/
devp->state = FLASH_STOP;
/* Bus release.*/

View File

@ -41,9 +41,10 @@
#define M25Q_CMD_RESET_ENABLE 0x66
#define M25Q_CMD_RESET_MEMORY 0x99
#define M25Q_CMD_READ_ID 0x9F
#define M25Q_CMD_MULTIPLE_IO_READ_ID 0xAF
#define M25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A
#define M25Q_CMD_READ 0x03
#define M25Q_CMD_FAST_READ 0x08
#define M25Q_CMD_FAST_READ 0x0B
#define M25Q_CMD_WRITE_ENABLE 0x06
#define M25Q_CMD_WRITE_DISABLE 0x04
#define M25Q_CMD_READ_STATUS_REGISTER 0x05
@ -111,6 +112,15 @@
#define M25Q_BUS_MODE M25Q_BUS_MODE_QSPI4L
#endif
/**
* @brief Number of dummy cycles for fast read (1..15).
* @details This is the number of dummy cycles to be used for fast read
* operations.
*/
#if !defined(M25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__)
#define M25Q_READ_DUMMY_CYCLES 8
#endif
/**
* @brief Switch QSPI bus width on initialization.
* @details A bus width initialization is performed by writing the
@ -185,6 +195,17 @@
#error "M25Q_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) && \
(M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI1L) && \
(M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI2L) && \
(M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI4L)
#error "invalid M25Q_BUS_MODE selected"
#endif
#if (M25Q_READ_DUMMY_CYCLES < 1) || (M25Q_READ_DUMMY_CYCLES > 15)
#error "invalid M25Q_READ_DUMMY_CYCLES value (1..15)"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@ -250,6 +271,10 @@ typedef struct {
*/
uint32_t qspi_mode;
#endif
/**
* @brief Device ID and unique ID.
*/
uint8_t device_id[20];
} M25QDriver;
/*===========================================================================*/

View File

@ -211,6 +211,22 @@ void qspi_lld_stop(QSPIDriver *qspip) {
*/
void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp) {
#if STM32_USE_STM32_D1_WORKAROUND == TRUE
/* If it is a command without address and alternate phases then the command
is sent as an alternate byte, the command phase is suppressed.*/
if ((cmdp->cfg & (QSPI_CFG_ADDR_MODE_MASK | QSPI_CFG_ALT_MODE_MASK)) == 0U) {
uint32_t cfg;
/* The command mode field is copied in the alternate mode field. All
other fields are not used in this scenario.*/
cfg = (cmdp->cfg & QSPI_CFG_CMD_MODE_MASK) << 6U;
qspip->qspi->DLR = 0U;
qspip->qspi->ABR = cmdp->cfg & QSPI_CFG_CMD_MASK;
qspip->qspi->CCR = cfg;
return;
}
#endif
qspip->qspi->DLR = 0U;
qspip->qspi->ABR = cmdp->alt;
qspip->qspi->CCR = cmdp->cfg;

View File

@ -31,6 +31,17 @@
/* Driver constants. */
/*===========================================================================*/
/**
* @name DCR register options
* @{
*/
#define STM32_DCR_CK_MODE (1U << 0U)
#define STM32_DCR_CSHT_MASK (7U << 8U)
#define STM32_DCR_CSHT(n) ((n) << 8U)
#define STM32_DCR_FSIZE_MASK (31U << 16U)
#define STM32_DCR_FSIZE(n) ((n) << 16U)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
@ -85,6 +96,17 @@
#if !defined(STM32_QSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
#define STM32_QSPI_DMA_ERROR_HOOK(qspip) osalSysHalt("DMA failure")
#endif
/**
* @brief Enables a workaround for a STM32L476 QUADSPI errata.
* @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an
* input when the command is sent in dual or quad SPI mode".
* This workaround makes commands without address or data phases
* to be sent as alternate bytes.
*/
#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__)
#define STM32_USE_STM32_D1_WORKAROUND TRUE
#endif
/** @} */
/*===========================================================================*/

View File

@ -33,7 +33,7 @@
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/>
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&lt;contentList&gt;&lt;content id=&quot;id[2]-id-m25qStart-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;id[1]-id-m25qStart-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;id[0]-id-m25qStart-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cr2-adc_lld_start_conversion-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CR2-adc-null-port_wait_for_interrupt-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CR2-adc-adcp-adc_lld_start_conversion-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cfg-cmdp-qspiSend-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CR-qspi-qspip-qspi_lld_send-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CCR-qspi-qspip-qspi_lld_send-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cfg-cmdp-qspiReceive-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;r2-(format)&quot; val=&quot;4&quot;/&gt;&lt;/contentList&gt;"/>
<stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&lt;contentList&gt;&lt;content id=&quot;CCR-qspi-qspip-qspi_lld_receive-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cfg-cmdp-qspi_lld_receive-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;id[2]-id-m25qStart-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;id[1]-id-m25qStart-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;id[0]-id-m25qStart-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;AFRL-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;AFRH-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;ODR-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;IDR-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;PUPDR-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;OSPEEDR-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;MODER-gpiop-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;afrh-config-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;moder-config-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;config-initgpio-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;r2-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cfg-cmdp-qspiReceive-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CCR-qspi-qspip-qspi_lld_send-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CR-qspi-qspip-qspi_lld_send-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cfg-cmdp-qspiSend-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CR2-adc-adcp-adc_lld_start_conversion-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;CR2-adc-null-port_wait_for_interrupt-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cr2-adc_lld_start_conversion-(format)&quot; val=&quot;4&quot;/&gt;&lt;content id=&quot;cmd-flash_cmd_receive-(format)&quot; val=&quot;4&quot;/&gt;&lt;/contentList&gt;"/>
<stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;globalVariableList/&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;memoryBlockExpressionList/&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="./build/ch.elf"/>

View File

@ -21,7 +21,7 @@
const QSPIConfig qspicfg1 = {
NULL,
0
STM32_DCR_FSIZE(24) | STM32_DCR_CSHT(1)
};
qspi_command_t cmd_read_id = {
@ -63,6 +63,7 @@ static THD_FUNCTION(Thread1, arg) {
* Application entry point.
*/
int main(void) {
flash_error_t err;
/*
* System initializations.
@ -89,8 +90,11 @@ int main(void) {
*/
m25qObjectInit(&m25q);
m25qStart(&m25q, &m25qcfg1);
// qspiStart(&QSPID1, &qspicfg1);
// qspiReceive(&QSPID1, &cmd_read_id, 17, buffer);
/* Reading it back.*/
err = flashRead(&m25q, 0, buffer, 128);
if (err != FLASH_NO_ERROR)
chSysHalt("read error");
/*
* Normal main() thread activity, in this demo it does nothing.