Compare commits

...

4 Commits

Author SHA1 Message Date
Michal Lenc
5743edd0e9 arch/arm/src/samv7/sam_qspi_spi.c: add support for SPI_SETDELAY
This commit adds support for SPI_SETDELAY operation on SAMv7 QSPI
peripheral running in SPI mode. The logic is the same as for standard
SPI peripheral, just different registers. The change allows to set
custom delays between transfers, chip selects and so on.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
2025-11-27 22:46:03 +08:00
Michal Lenc
edf3cc55a5 drivers/mtd/w25: support custom SPI transfers delay
This commit adds SPI_SETDELAY interface if CONFIG_SPI_DELAY_CONTROL
option is set. This allows to set custom delay between SPI transfers,
chip selects and so on.

Default values are set to 0. W25 SPI NOR flash works with them and
I haven't found any other values in the datasheet.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
2025-11-27 22:27:40 +08:00
Jukka Laitinen
58978490ad fs/fat: Ignore multiple consecutive slashes in long file names
This fixes the same issue as in 1f15756156, for long file names.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
2025-11-27 22:26:56 +08:00
hujun5
0c6fe04ef7 Revert "sched_idletask: remove the check for whether tcb is NULL"
This reverts commit 8f91054b1d.

Signed-off-by: hujun5 <hujun5@xiaomi.com>
2025-11-27 08:26:53 -03:00
5 changed files with 170 additions and 12 deletions

View File

@@ -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
*

View File

@@ -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

View File

@@ -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
}
/****************************************************************************

View File

@@ -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;

View File

@@ -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;
}