Skip to content

Commit e8d5abe

Browse files
committed
[bsp][n32] n32hxxx: bound the XSPI waits and fix I2C/SPI/NAND edge cases
- qspi: both XSPI variants poll the status flags with no bound, so an unresponsive bus hangs the caller and silently defeats the timeout it passed in. Route every wait through the timeout-carrying helpers, return -RT_ETIMEOUT and disable the controller on failure, and replace the "poll then send" loops with one bounded wait per element. - hard_i2c: the interrupt receive path programs the BYTENUM window once and never reloads it, so a longer message was truncated and still reported as success; refuse it with -RT_EINVAL (enable RX DMA for longer reads) instead of capping XferSize. Stop capping the transmit byte count at the window size as well: BYTENUM counts received bytes only, and the cap stopped feeding DAT after byte 255 while TXDATE stayed asserted. Reject RT_I2C_NO_START/RT_I2C_NO_STOP on the series without frame chaining, where they would silently become a fresh START and a STOP, and tear the DMA channel down when the address phase times out instead of leaving it armed against a buffer about to unwind. - spi: the H7xx LLI chain advanced the memory side by SPI_DMA_BLOCK_MAX bytes although BlkTfrSize counts elements, so a 16-bit transfer walked half a word early per node; advance by elements and scale both the chunk offset and the staging buffer by the data width. Propagate the DMA arm failure that was ignored. - nand: an odd data length has no halfword-only encoding on the 16-bit bus and padding would program a byte the caller never asked for, so refuse it before the command phase; issue the empty-page dummy store as a halfword there too, where 8-bit AHB writes are unsupported. - Kconfig: gate the Ethernet/SDRAM/LCD/QSPI/NAND options behind BSP_PERIPH_PIN_CFG_READY on all three boards. The peripheral clock and IO are not configured for these boards yet, so selecting one of them builds a driver whose pins stay in the reset function.
1 parent bca1bde commit e8d5abe

8 files changed

Lines changed: 358 additions & 88 deletions

File tree

bsp/n32/n32hxxx/libraries/N32_Drivers/drivers/drv_hard_i2c.c

Lines changed: 101 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -626,23 +626,33 @@ static rt_err_t n32_i2c_master_seq_receive_it(struct n32_i2c *i2c, uint16_t DevA
626626

627627
if (i2c->transfer.state == I2C_READY)
628628
{
629+
/* A master receive fits in a single BYTENUM window: the counter is
630+
* loaded once below and this path never reloads it, so the BSF
631+
* completion ends the transfer after that many bytes. A longer message
632+
* would be silently truncated yet still reported as success; refuse it
633+
* instead. BYTENUM is 8 bits (the SDK's own setter takes a uint8_t), so
634+
* the count cannot be widened either. Only the DMA path reloads the
635+
* window as it drains.
636+
*
637+
* n32_i2c_master_xfer screens the same condition before dispatching, so
638+
* the caller gets an errno; this check keeps the invariant stated where
639+
* the window is actually programmed.
640+
*/
641+
if (Size > MAX_NBYTE_SIZE)
642+
{
643+
LOG_E("I2C IT receive of %u bytes exceeds the %u-byte BYTENUM window, enable RX DMA for longer reads", (unsigned int)Size, (unsigned int)MAX_NBYTE_SIZE);
644+
return -RT_EINVAL;
645+
}
646+
629647
/* Set transfer parameters */
630648
i2c->transfer.state = I2C_BUSY_RX;
631649
i2c->transfer.pBuffPtr = pData;
632650
i2c->transfer.XferCount = Size;
633651
i2c->transfer.XferOptions = XferOptions;
634652
i2c->i2c_isr_callback = i2c_master_ev_isr_handler_it;
635653

636-
/* If Size > MAX_NBYTE_SIZE, use reload mode */
637-
if (Size > MAX_NBYTE_SIZE)
638-
{
639-
i2c->transfer.XferSize = MAX_NBYTE_SIZE;
640-
}
641-
else
642-
{
643-
i2c->transfer.XferSize = i2c->transfer.XferCount;
644-
}
645-
654+
/* One window covers the whole transfer - see the size check above */
655+
i2c->transfer.XferSize = i2c->transfer.XferCount;
646656

647657
#if defined(SOC_SERIES_N32H49x)
648658
I2C_EnableByteNum(i2c->config->Instance, ENABLE);
@@ -769,15 +779,14 @@ static rt_err_t n32_i2c_master_seq_send_it(struct n32_i2c *i2c, uint16_t DevAddr
769779
i2c->transfer.XferOptions = XferOptions;
770780
i2c->i2c_isr_callback = i2c_master_ev_isr_handler_it;
771781

772-
/* If Size > MAX_NBYTE_SIZE, use reload mode */
773-
if (Size > MAX_NBYTE_SIZE)
774-
{
775-
i2c->transfer.XferSize = MAX_NBYTE_SIZE;
776-
}
777-
else
778-
{
779-
i2c->transfer.XferSize = i2c->transfer.XferCount;
780-
}
782+
/* No 255-byte window here: BYTENUM counts received bytes only, and this
783+
* ISR feeds DAT one byte per TXDATE interrupt, so XferSize is nothing
784+
* more than the remaining byte count. Capping it at MAX_NBYTE_SIZE made
785+
* the TXDATE branch stop feeding after the 255th byte of a longer
786+
* message - the tail was never sent while TXDATE stayed asserted and
787+
* stormed this handler until the caller timed out.
788+
*/
789+
i2c->transfer.XferSize = i2c->transfer.XferCount;
781790

782791
/* Wait for the previous STOP to complete. Toggling PE here would not
783792
* reset the state machine while BUSY is set, and could hold the lines.
@@ -904,7 +913,14 @@ static rt_err_t n32_i2c_master_seq_receive_dma(struct n32_i2c *i2c, uint16_t Dev
904913
rt_err_t start_ret = n32_i2c_master_start_addr(i2c, (uint8_t)DevAddress, I2C_DIRECTION_RECV);
905914
if (start_ret != RT_EOK)
906915
{
907-
i2c->transfer.state = I2C_READY;
916+
/* The DMA request and the BUF/ERR interrupts are armed by
917+
* now and the DMA channel still targets the caller's
918+
* buffer, so resetting only the state would let a late
919+
* byte write through a stack frame that is about to
920+
* unwind. The timeout paths of n32_i2c_master_start_addr
921+
* raise no error interrupt that could tear this down, so
922+
* do it here. */
923+
I2C_ABORT_ON_TIMEOUT(i2c);
908924
return start_ret;
909925
}
910926
}
@@ -1010,7 +1026,14 @@ static rt_err_t n32_i2c_master_seq_send_dma(struct n32_i2c *i2c, uint16_t DevAdd
10101026
rt_err_t start_ret = n32_i2c_master_start_addr(i2c, (uint8_t)DevAddress, I2C_DIRECTION_SEND);
10111027
if (start_ret != RT_EOK)
10121028
{
1013-
i2c->transfer.state = I2C_READY;
1029+
/* The DMA request and the BUF/ERR interrupts are armed by
1030+
* now and the DMA channel still targets the caller's
1031+
* buffer, so resetting only the state would let a late
1032+
* byte write through a stack frame that is about to
1033+
* unwind. The timeout paths of n32_i2c_master_start_addr
1034+
* raise no error interrupt that could tear this down, so
1035+
* do it here. */
1036+
I2C_ABORT_ON_TIMEOUT(i2c);
10141037
return start_ret;
10151038
}
10161039
}
@@ -1075,6 +1098,51 @@ static rt_ssize_t n32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
10751098
i2c_obj = rt_container_of(bus, struct n32_i2c, i2c_bus);
10761099
completion = &i2c_obj->completion;
10771100

1101+
#if defined(SOC_SERIES_N32H49x) || defined(SOC_SERIES_N32H47x_48x)
1102+
/* This series cannot chain frames, so neither flag can be honoured. The
1103+
* mode constants the translate step below derives from them are all
1104+
* 0x00000000U on this series (see the definitions at the top of this file),
1105+
* so XferOptions is always zero here and changes nothing in the CTRL2
1106+
* write. Every message instead re-runs the START + 7-bit address sequence
1107+
* in its own per-message setup, and completion always ends in a STOP
1108+
* (STOPGEN in i2c_it_completion_done, or the BYTENUM auto-stop on the DMA
1109+
* receive). A caller asking for RT_I2C_NO_START or RT_I2C_NO_STOP would
1110+
* therefore silently get a fresh START and a STOP instead of a repeated
1111+
* start -- a different bus transaction than the one requested, which some
1112+
* slaves reject. Refuse it rather than change it behind the caller's back;
1113+
* a repeated-start sequence needs the frame chaining this controller
1114+
* lacks.
1115+
*/
1116+
for (i = 0; i < num; i++)
1117+
{
1118+
if (msgs[i].flags & (RT_I2C_NO_START | RT_I2C_NO_STOP))
1119+
{
1120+
LOG_E("I2C: RT_I2C_NO_START/RT_I2C_NO_STOP are not supported on this series (no frame chaining), msg[%d] flags=0x%x", i, msgs[i].flags);
1121+
return -RT_ENOSYS;
1122+
}
1123+
1124+
/* A receive that the interrupt path has to serve fits in one BYTENUM
1125+
* window, and that path never reloads the counter. Screen it here as
1126+
* well as in the receive setup below, because a rejection raised from
1127+
* inside the transfer is reported as a message count rather than an
1128+
* errno (see "out:"), so the caller would only see a silent short
1129+
* read. The test mirrors this function's own DMA dispatch: the
1130+
* interrupt path is taken when RX DMA is off or the message is too
1131+
* short for it.
1132+
*/
1133+
if ((msgs[i].flags & RT_I2C_RD) && (msgs[i].len > MAX_NBYTE_SIZE))
1134+
{
1135+
rt_bool_t rx_dma_ready = (i2c_obj->i2c_dma_flag & I2C_USING_RX_DMA_FLAG) ? RT_TRUE : RT_FALSE;
1136+
1137+
if ((rx_dma_ready != RT_TRUE) || (msgs[i].len < DMA_TRANS_MIN_LEN))
1138+
{
1139+
LOG_E("I2C IT receive of %u bytes exceeds the %u-byte BYTENUM window, enable RX DMA for longer reads", (unsigned int)msgs[i].len, (unsigned int)MAX_NBYTE_SIZE);
1140+
return -RT_EINVAL;
1141+
}
1142+
}
1143+
}
1144+
#endif
1145+
10781146
LOG_D("xfer start %d mags", num);
10791147
for (i = 0; i < (num - 1); i++)
10801148
{
@@ -1890,12 +1958,23 @@ static void i2c_master_ev_isr_handler_it(struct n32_i2c *drv_i2c)
18901958
}
18911959
}
18921960

1893-
/* Byte Sequence Finished - independent check, handles completion when XferCount == 0 */
1961+
/* Byte Sequence Finished - only reachable with XferCount == 0, so completing
1962+
* unconditionally is correct: the RX setup refuses sizes beyond the single
1963+
* BYTENUM window it programs, and a master transmit is not windowed at all -
1964+
* its last byte is fed to DAT exactly when XferCount reaches zero. A nonzero
1965+
* XferCount here means the two setups above drifted out of sync, which is
1966+
* worth a trace rather than silently truncating the message.
1967+
*/
18941968
if ((itflags & I2C_STS1_BSF) && (itsources & I2C_CTRL2_BUFINTEN))
18951969
{
18961970
/* Clear BSF flag */
18971971
I2C_ClrIntPendingBit(drv_i2c->config->Instance, I2C_INT_BSF);
18981972

1973+
if (drv_i2c->transfer.XferCount != 0U)
1974+
{
1975+
LOG_W("I2C BSF with %u bytes still queued", (unsigned int)drv_i2c->transfer.XferCount);
1976+
}
1977+
18991978
/* Transfer complete - BYTENUM expired (RX) or all bytes sent (TX) */
19001979
i2c_it_completion_done(drv_i2c);
19011980
}

bsp/n32/n32hxxx/libraries/N32_Drivers/drivers/drv_nand.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,20 @@ static rt_err_t _write_page(struct rt_mtd_nand_device *device,
662662
uint32_t i;
663663
rt_err_t ret;
664664

665+
#ifdef BSP_USING_NAND_BUS_WIDTH_16B
666+
/* 16-bit NAND has no 8-bit store (see the data phase below), so an odd
667+
* data_len has no halfword-only encoding: its trailing byte could only
668+
* leave as an 8-bit write, and padding would program a byte the caller
669+
* never asked for. Refuse it before the command phase, so the chip is
670+
* never left in the middle of a program sequence.
671+
*/
672+
if (data_len & 1U)
673+
{
674+
LOG_E("page %d: 16-bit NAND needs an even data length, got %u", (int)page, (unsigned int)data_len);
675+
return -RT_EINVAL;
676+
}
677+
#endif
678+
665679
/* Command phase: WRITE_1ST + column(2x 0) + row(NAND_ROW_ADDR_CYCLES) */
666680
*(__IO uint8_t *)(bank | NAND_CMD_AREA) = NAND_CMD_WRITE_1ST;
667681
*(__IO uint8_t *)(bank | NAND_ADDR_AREA) = 0x00;
@@ -686,7 +700,8 @@ static rt_err_t _write_page(struct rt_mtd_nand_device *device,
686700
* 16-bit NAND: 8-bit AHB writes are NOT supported (see FEMC manual
687701
* "supported memories and operations"), so data must be written as
688702
* 16-bit accesses. If the source buffer is not 16-bit aligned, copy
689-
* it into an aligned temporary buffer first.
703+
* it into an aligned temporary buffer first. An odd data_len was
704+
* refused at the top of this function.
690705
*/
691706
if (((uint32_t)data & 0x1U) == 0U)
692707
{
@@ -716,11 +731,6 @@ static rt_err_t _write_page(struct rt_mtd_nand_device *device,
716731
}
717732
rt_free(tmp);
718733
}
719-
/* odd trailing byte */
720-
if (data_len & 1)
721-
{
722-
*(__IO uint8_t *)(bank | NAND_DATA_AREA) = data[data_len - 1];
723-
}
724734
#else
725735
for (i = 0; i < data_len; i++)
726736
{
@@ -730,7 +740,14 @@ static rt_err_t _write_page(struct rt_mtd_nand_device *device,
730740
}
731741
else
732742
{
743+
/* No payload: one store still has to be issued so the data phase clocks
744+
* out. 16-bit NAND rejects 8-bit AHB writes (see the note above), so the
745+
* dummy element must be halfword-sized on that bus. */
746+
#ifdef BSP_USING_NAND_BUS_WIDTH_16B
747+
*(__IO uint16_t *)(bank | NAND_DATA_AREA) = 0x0000;
748+
#else
733749
*(__IO uint8_t *)(bank | NAND_DATA_AREA) = 0x00;
750+
#endif
734751
}
735752

736753
/* spare area write not implemented yet */

0 commit comments

Comments
 (0)