1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/*
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2026-01-24 ox-horse first version
*/
#ifndef __DRV_SPI_H__
#define __DRV_SPI_H__
#include <rtthread.h>
#include "rtdevice.h"
#include <rthw.h>
#include <drv_common.h>
#include "drv_dma.h"
#include <ipc/completion.h>
#include "drv_config.h"
#ifdef __cplusplus
extern "C" {
#endif
rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin);
#ifdef __cplusplus
}
#endif
struct n32_spi_config
{
SPI_Module *SPIx;
char *bus_name;
IRQn_Type irq_type;
struct dma_config *dma_rx, *dma_tx;
};
struct n32_spi_device
{
rt_uint32_t pin;
char *bus_name;
char *device_name;
};
#define SPI_USING_RX_DMA_FLAG (1 << 0)
#define SPI_USING_TX_DMA_FLAG (1 << 1)
/* Max elements (data items) of a single DMA block (12-bit BlkTfrSize) */
#define SPI_DMA_BLOCK_MAX (4095U)
/* Number of LLI chain nodes per DMA leg (sizes lli_tx/lli_rx) */
#define SPI_DMA_CHAIN_NODES (16U)
#define SPI_DMA_CHAIN_MAX (SPI_DMA_BLOCK_MAX * SPI_DMA_CHAIN_NODES)
/* Max elements of a single DMA arm: spixfer chunks every message at this
* size. A N32H7xx DMA arm stalls past ~4128 items at the 20MHz top rate
* (silicon-level: the LLI chain is verified intact and frozen mid-node;
* sharp 4128 PASS / 4136 FAIL boundary, and the ceiling scales with the
* bit clock so a 4096-item arm passes at every rate). 4096 items = 2 LLI
* nodes (4095+1) -- the same per-arm shape as a standalone 4096-element
* message. */
#define SPI_DMA_ARM_MAX (4096U)
typedef enum
{
SPI_Tx_Rx = 0U,
SPI_Tx,
SPI_Rx,
SPI_Idle,
} SPI_Work_Direct_t;
/* n32 spi dirver class */
struct n32_spi
{
struct n32_spi_config *config;
struct rt_spi_configuration *cfg;
SPI_InitType SPI_InitStructure;
SPI_Work_Direct_t Direct;
#if defined(SOC_SERIES_N32H7xx)
struct
{
rt_bool_t DMA_Tx_Init;
DMA_ChInitType TX_DMA_ChInitStr;
rt_bool_t DMA_Rx_Init;
DMA_ChInitType RX_DMA_ChInitStr;
/* LLI node arrays: seamless single-task DMA for > SPI_DMA_BLOCK_MAX */
DMA_LinkListItemType lli_rx[SPI_DMA_CHAIN_NODES];
DMA_LinkListItemType lli_tx[SPI_DMA_CHAIN_NODES];
} dma;
#elif defined(SOC_SERIES_N32H49x) || defined(SOC_SERIES_N32H47x_48x)
struct
{
rt_bool_t DMA_Tx_Init;
DMA_InitType TX_DMA_ChInitStr;
rt_bool_t DMA_Rx_Init;
DMA_InitType RX_DMA_ChInitStr;
} dma;
#endif
rt_uint8_t spi_dma_flag;
/* TRUE while a 4-wire full-duplex MASTER receive-only message is being
* armed: the TX DMA source is then the static 0xFF fill buffer, and
* n32_spi_dma_arm re-points every LLI TX node at its base. Read only
* inside n32_spi_dma_arm; set/cleared around the SPI_DMA_TransmitReceive
* call in SPI_DMA_Receive. Per-bus messages are serialized by the
* RT-Thread bus lock and no ISR reads the flag, so a plain rt_bool_t is
* race-free. Unused on non-H7 series. */
rt_bool_t fd_rxonly_dummy_tx;
/* TRUE while a non-first chunk of a 4-wire full-duplex message is being
* armed: spixfer keeps the SPI engine on across chunk boundaries (only
* the message tail disables), so SPI_DMA_TransmitReceive re-arms the
* live engine warm (no SPIEN drop/re-enable) instead of cold-starting
* it. Read only inside SPI_DMA_TransmitReceive; set at the top of every
* chunk in spixfer. Per-bus messages are serialized by the RT-Thread
* bus lock and no ISR reads the flag, so a plain rt_bool_t is
* race-free. Unused on non-H7 series. */
rt_bool_t fd_chunk_cont;
struct rt_spi_bus spi_bus;
struct rt_completion cpt;
};
#endif /*__DRV_SPI_H__ */
|