mirror of
https://github.com/apache/nuttx.git
synced 2025-12-06 17:23:49 +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);
|
||||
static uint32_t qspi_spi_setfrequency(struct spi_dev_s *dev,
|
||||
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_setbits(struct spi_dev_s *dev, int nbits);
|
||||
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,
|
||||
.select = qspi_spi_select,
|
||||
.setfrequency = qspi_spi_setfrequency,
|
||||
#ifdef CONFIG_SPI_DELAY_CONTROL
|
||||
.setdelay = qspi_spi_setdelay,
|
||||
#endif
|
||||
.setmode = qspi_spi_setmode,
|
||||
.setbits = qspi_spi_setbits,
|
||||
.status = sam_qspi_status,
|
||||
@@ -398,6 +406,102 @@ static uint32_t qspi_spi_setfrequency(struct spi_dev_s *dev,
|
||||
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
|
||||
*
|
||||
|
||||
@@ -1352,6 +1352,38 @@ config W25_SPIFREQUENCY
|
||||
int "W25 SPI Frequency"
|
||||
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
|
||||
bool "W25 Read-Only FLASH"
|
||||
default n
|
||||
|
||||
@@ -354,6 +354,11 @@ static void w25_lock(FAR struct spi_dev_s *spi)
|
||||
SPI_SETBITS(spi, 8);
|
||||
SPI_HWFEATURES(spi, 0);
|
||||
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';
|
||||
|
||||
/* Ignore sequences of //... in the filename */
|
||||
|
||||
while (node && *node == '/')
|
||||
{
|
||||
node++;
|
||||
}
|
||||
|
||||
/* Return the remaining sub-string and the terminating character. */
|
||||
|
||||
*terminator = (char)ch;
|
||||
|
||||
@@ -60,18 +60,28 @@ bool sched_idletask(void)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = this_task();
|
||||
|
||||
DEBUGASSERT(rtcb);
|
||||
|
||||
/* 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.
|
||||
/* If called early in the initialization sequence, the tasks lists may not
|
||||
* have been initialized and, in that case, rtcb may be NULL.
|
||||
*/
|
||||
|
||||
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