mirror of
https://github.com/apache/nuttx.git
synced 2025-12-07 10:03:38 +08:00
Compare commits
4 Commits
70455f1890
...
5743edd0e9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5743edd0e9 | ||
|
|
edf3cc55a5 | ||
|
|
58978490ad | ||
|
|
0c6fe04ef7 |
@@ -112,6 +112,11 @@ static void qspi_spi_select(struct spi_dev_s *dev, uint32_t devid,
|
|||||||
bool selected);
|
bool selected);
|
||||||
static uint32_t qspi_spi_setfrequency(struct spi_dev_s *dev,
|
static uint32_t qspi_spi_setfrequency(struct spi_dev_s *dev,
|
||||||
uint32_t frequency);
|
uint32_t frequency);
|
||||||
|
#ifdef CONFIG_SPI_DELAY_CONTROL
|
||||||
|
static int qspi_spi_setdelay(struct spi_dev_s *dev, uint32_t startdelay,
|
||||||
|
uint32_t stopdelay, uint32_t csdelay,
|
||||||
|
uint32_t ifdelay);
|
||||||
|
#endif
|
||||||
static void qspi_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode);
|
static void qspi_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode);
|
||||||
static void qspi_spi_setbits(struct spi_dev_s *dev, int nbits);
|
static void qspi_spi_setbits(struct spi_dev_s *dev, int nbits);
|
||||||
static uint32_t qspi_spi_send(struct spi_dev_s *dev, uint32_t wd);
|
static uint32_t qspi_spi_send(struct spi_dev_s *dev, uint32_t wd);
|
||||||
@@ -135,6 +140,9 @@ static const struct spi_ops_s g_spiops =
|
|||||||
.lock = qspi_spi_lock,
|
.lock = qspi_spi_lock,
|
||||||
.select = qspi_spi_select,
|
.select = qspi_spi_select,
|
||||||
.setfrequency = qspi_spi_setfrequency,
|
.setfrequency = qspi_spi_setfrequency,
|
||||||
|
#ifdef CONFIG_SPI_DELAY_CONTROL
|
||||||
|
.setdelay = qspi_spi_setdelay,
|
||||||
|
#endif
|
||||||
.setmode = qspi_spi_setmode,
|
.setmode = qspi_spi_setmode,
|
||||||
.setbits = qspi_spi_setbits,
|
.setbits = qspi_spi_setbits,
|
||||||
.status = sam_qspi_status,
|
.status = sam_qspi_status,
|
||||||
@@ -398,6 +406,102 @@ static uint32_t qspi_spi_setfrequency(struct spi_dev_s *dev,
|
|||||||
return actual;
|
return actual;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: qspi_spi_setdelay
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set the QSPI Delays in nanoseconds. Optional.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dev - Device-specific state data
|
||||||
|
* startdelay - The delay between CS active and first CLK
|
||||||
|
* stopdelay - The delay between last CLK and CS inactive
|
||||||
|
* csdelay - The delay between CS inactive and CS active again
|
||||||
|
* ifdelay - The delay between frames
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Returns 0 if ok
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_DELAY_CONTROL
|
||||||
|
static int qspi_spi_setdelay(struct spi_dev_s *dev, uint32_t startdelay,
|
||||||
|
uint32_t stopdelay, uint32_t csdelay,
|
||||||
|
uint32_t ifdelay)
|
||||||
|
{
|
||||||
|
struct sam_spidev_s *spi = &g_spidev;
|
||||||
|
uint64_t dlybs;
|
||||||
|
uint64_t dlybct;
|
||||||
|
uint64_t dlybcs;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
spiinfo("startdelay=%" PRIu32 "\n", startdelay);
|
||||||
|
spiinfo("stopdelay=%" PRIu32 "\n", stopdelay);
|
||||||
|
spiinfo("csdelay=%" PRIu32 "\n", csdelay);
|
||||||
|
spiinfo("ifdelay=%" PRIu32 "\n", ifdelay);
|
||||||
|
|
||||||
|
/* startdelay = DLYBS: Delay Before SPCK.
|
||||||
|
* This field defines the delay from NPCS valid to the first valid SPCK
|
||||||
|
* transition. When DLYBS equals zero, the NPCS valid to SPCK transition is
|
||||||
|
* 1/2 the SPCK clock period.
|
||||||
|
* Otherwise, the following equations determine the delay:
|
||||||
|
*
|
||||||
|
* Delay Before SPCK = DLYBS / SPI_CLK
|
||||||
|
*
|
||||||
|
* For a 2uS delay
|
||||||
|
*
|
||||||
|
* DLYBS = SPI_CLK * 0.000002 = SPI_CLK / 500000
|
||||||
|
*
|
||||||
|
* TODO: Check for boundaries!
|
||||||
|
*/
|
||||||
|
|
||||||
|
dlybs = (SAM_QSPI_CLOCK * startdelay) / 1000000000;
|
||||||
|
regval = qspi_getreg(spi, SAM_QSPI_SCR_OFFSET);
|
||||||
|
regval &= ~QSPI_SCR_DLYBS_MASK;
|
||||||
|
regval |= (uint32_t) dlybs << QSPI_SCR_DLYBS_SHIFT;
|
||||||
|
qspi_putreg(spi, regval, SAM_QSPI_SCR_OFFSET);
|
||||||
|
|
||||||
|
/* ifdelay = DLYBCT: Delay Between Consecutive Transfers.
|
||||||
|
* This field defines the delay between two consecutive transfers with the
|
||||||
|
* same peripheral without removing the chip select. The delay is always
|
||||||
|
* inserted after each transfer and before removing the chip select if
|
||||||
|
* needed.
|
||||||
|
*
|
||||||
|
* Delay Between Consecutive Transfers = (32 x DLYBCT) / SPI_CLK
|
||||||
|
*
|
||||||
|
* For a 5uS delay:
|
||||||
|
*
|
||||||
|
* DLYBCT = SPI_CLK * 0.000005 / 32 = SPI_CLK / 200000 / 32
|
||||||
|
*/
|
||||||
|
|
||||||
|
dlybct = (SAM_QSPI_CLOCK * ifdelay) / 1000000000 / 32;
|
||||||
|
regval = qspi_getreg(spi, SAM_QSPI_MR_OFFSET);
|
||||||
|
regval &= ~(QSPI_MR_DLYBCT_MASK);
|
||||||
|
regval |= (uint32_t) dlybct << QSPI_MR_DLYBCT_SHIFT;
|
||||||
|
qspi_putreg(spi, regval, SAM_QSPI_MR_OFFSET);
|
||||||
|
|
||||||
|
/* csdelay = DLYBCS: Delay Between Chip Selects.
|
||||||
|
* This field defines the delay between the inactivation and the activation
|
||||||
|
* of NPCS. The DLYBCS time guarantees non-overlapping chip selects and
|
||||||
|
* solves bus contentions in case of peripherals having long data float
|
||||||
|
* times. If DLYBCS is lower than 6, six peripheral clock periods are
|
||||||
|
* inserted by default.
|
||||||
|
*
|
||||||
|
* Delay Between Chip Selects = DLYBCS / SPI_CLK
|
||||||
|
*
|
||||||
|
* DLYBCS = SPI_CLK * Delay
|
||||||
|
*/
|
||||||
|
|
||||||
|
dlybcs = (SAM_QSPI_CLOCK * csdelay) / 1000000000;
|
||||||
|
regval = qspi_getreg(spi, SAM_QSPI_MR_OFFSET);
|
||||||
|
regval &= ~(QSPI_MR_DLYCS_MASK);
|
||||||
|
regval |= (uint32_t) dlybcs << QSPI_MR_DLYCS_SHIFT;
|
||||||
|
qspi_putreg(spi, regval, SAM_QSPI_MR_OFFSET);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: qspi_spi_setmode
|
* Name: qspi_spi_setmode
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1352,6 +1352,38 @@ config W25_SPIFREQUENCY
|
|||||||
int "W25 SPI Frequency"
|
int "W25 SPI Frequency"
|
||||||
default 20000000
|
default 20000000
|
||||||
|
|
||||||
|
config W25_START_DELAY
|
||||||
|
int "W25 SPI start delay"
|
||||||
|
depends on SPI_DELAY_CONTROL
|
||||||
|
range 0 1000000
|
||||||
|
default 0
|
||||||
|
---help---
|
||||||
|
The delay between CS active and first CLK. In ns.
|
||||||
|
|
||||||
|
config W25_STOP_DELAY
|
||||||
|
int "W25 SPI stop delay"
|
||||||
|
depends on SPI_DELAY_CONTROL
|
||||||
|
range 0 1000000
|
||||||
|
default 0
|
||||||
|
---help---
|
||||||
|
The delay between last CLK and CS inactive. In ns.
|
||||||
|
|
||||||
|
config W25_CS_DELAY
|
||||||
|
int "W25 SPI chip select delay"
|
||||||
|
depends on SPI_DELAY_CONTROL
|
||||||
|
range 0 1000000
|
||||||
|
default 0
|
||||||
|
---help---
|
||||||
|
The delay between CS inactive and CS active again. In ns.
|
||||||
|
|
||||||
|
config W25_IFDELAY
|
||||||
|
int "W25 SPI frames delay"
|
||||||
|
depends on SPI_DELAY_CONTROL
|
||||||
|
range 0 1000000
|
||||||
|
default 0
|
||||||
|
---help---
|
||||||
|
The delay between consecutive frames. In ns.
|
||||||
|
|
||||||
config W25_READONLY
|
config W25_READONLY
|
||||||
bool "W25 Read-Only FLASH"
|
bool "W25 Read-Only FLASH"
|
||||||
default n
|
default n
|
||||||
|
|||||||
@@ -354,6 +354,11 @@ static void w25_lock(FAR struct spi_dev_s *spi)
|
|||||||
SPI_SETBITS(spi, 8);
|
SPI_SETBITS(spi, 8);
|
||||||
SPI_HWFEATURES(spi, 0);
|
SPI_HWFEATURES(spi, 0);
|
||||||
SPI_SETFREQUENCY(spi, CONFIG_W25_SPIFREQUENCY);
|
SPI_SETFREQUENCY(spi, CONFIG_W25_SPIFREQUENCY);
|
||||||
|
#ifdef CONFIG_SPI_DELAY_CONTROL
|
||||||
|
SPI_SETDELAY(spi, CONFIG_W25_START_DELAY,
|
||||||
|
CONFIG_W25_STOP_DELAY, CONFIG_W25_CS_DELAY,
|
||||||
|
CONFIG_W25_IFDELAY);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -607,6 +607,13 @@ static inline int fat_parselfname(FAR const char **path,
|
|||||||
|
|
||||||
dirinfo->fd_lfname[ndx] = '\0';
|
dirinfo->fd_lfname[ndx] = '\0';
|
||||||
|
|
||||||
|
/* Ignore sequences of //... in the filename */
|
||||||
|
|
||||||
|
while (node && *node == '/')
|
||||||
|
{
|
||||||
|
node++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the remaining sub-string and the terminating character. */
|
/* Return the remaining sub-string and the terminating character. */
|
||||||
|
|
||||||
*terminator = (char)ch;
|
*terminator = (char)ch;
|
||||||
|
|||||||
@@ -60,18 +60,28 @@ bool sched_idletask(void)
|
|||||||
{
|
{
|
||||||
FAR struct tcb_s *rtcb = this_task();
|
FAR struct tcb_s *rtcb = this_task();
|
||||||
|
|
||||||
DEBUGASSERT(rtcb);
|
/* If called early in the initialization sequence, the tasks lists may not
|
||||||
|
* have been initialized and, in that case, rtcb may be NULL.
|
||||||
/* The IDLE task TCB is distinguishable by a few things:
|
|
||||||
*
|
|
||||||
* (1) It always lies at the end of the task list,
|
|
||||||
* (2) It always has priority zero, and
|
|
||||||
* (3) It should have the TCB_FLAG_CPU_LOCKED flag set.
|
|
||||||
*
|
|
||||||
* In the non-SMP case, the IDLE task will also have PID=0, but that
|
|
||||||
* is not a portable test because there are multiple IDLE tasks with
|
|
||||||
* different PIDs in the SMP configuration.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return is_idle_task(rtcb);
|
DEBUGASSERT(rtcb != NULL || !OSINIT_TASK_READY());
|
||||||
|
if (rtcb != NULL)
|
||||||
|
{
|
||||||
|
/* The IDLE task TCB is distinguishable by a few things:
|
||||||
|
*
|
||||||
|
* (1) It always lies at the end of the task list,
|
||||||
|
* (2) It always has priority zero, and
|
||||||
|
* (3) It should have the TCB_FLAG_CPU_LOCKED flag set.
|
||||||
|
*
|
||||||
|
* In the non-SMP case, the IDLE task will also have PID=0, but that
|
||||||
|
* is not a portable test because there are multiple IDLE tasks with
|
||||||
|
* different PIDs in the SMP configuration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return is_idle_task(rtcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We must be on the IDLE thread if we are early in initialization */
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user