1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2023-03-24     spaceman          the first version
9  */
10 
11 #include "drv_lcd_spi_ext.h"
12 #include "stm32h7xx_hal.h"
13 
14 static SPI_HandleTypeDef* spi_handle;
15 
Set_SPI_Handle_Ext(SPI_HandleTypeDef * handle)16 void Set_SPI_Handle_Ext(SPI_HandleTypeDef *handle)
17 {
18     spi_handle = handle;
19 }
20 
21 /**
22  * @brief Handle SPI Communication Timeout.
23  * @param hspi: pointer to a SPI_HandleTypeDef structure that contains
24  *              the configuration information for SPI module.
25  * @param Flag: SPI flag to check
26  * @param Status: flag state to check
27  * @param Timeout: Timeout duration
28  * @param Tickstart: Tick start value
29  * @retval HAL status
30  */
LCD_SPI_WaitOnFlagUntilTimeout(SPI_HandleTypeDef * hspi,uint32_t Flag,FlagStatus Status,uint32_t Tickstart,uint32_t Timeout)31 HAL_StatusTypeDef LCD_SPI_WaitOnFlagUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Flag, FlagStatus Status,
32                                                  uint32_t Tickstart, uint32_t Timeout)
33 {
34     /* Wait until flag is set */
35     while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) == Status) {
36         /* Check for the Timeout */
37         if ((((HAL_GetTick() - Tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) {
38             return HAL_TIMEOUT;
39         }
40     }
41     return HAL_OK;
42 }
43 
44 /**
45  * @brief  Close Transfer and clear flags.
46  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
47  *               the configuration information for SPI module.
48  * @retval HAL_ERROR: if any error detected
49  *         HAL_OK: if nothing detected
50  */
LCD_SPI_CloseTransfer(SPI_HandleTypeDef * hspi)51 void LCD_SPI_CloseTransfer(SPI_HandleTypeDef *hspi)
52 {
53     uint32_t itflag = hspi->Instance->SR;
54 
55     __HAL_SPI_CLEAR_EOTFLAG(hspi);
56     __HAL_SPI_CLEAR_TXTFFLAG(hspi);
57 
58     /* Disable SPI peripheral */
59     __HAL_SPI_DISABLE(hspi);
60 
61     /* Disable ITs */
62     __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_TXP | SPI_IT_RXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | SPI_IT_FRE | SPI_IT_MODF));
63 
64     /* Disable Tx DMA Request */
65     CLEAR_BIT(hspi->Instance->CFG1, SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN);
66 
67     /* Report UnderRun error for non RX Only communication */
68     if (hspi->State != HAL_SPI_STATE_BUSY_RX) {
69         if ((itflag & SPI_FLAG_UDR) != 0UL) {
70             SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_UDR);
71             __HAL_SPI_CLEAR_UDRFLAG(hspi);
72         }
73     }
74 
75     /* Report OverRun error for non TX Only communication */
76     if (hspi->State != HAL_SPI_STATE_BUSY_TX) {
77         if ((itflag & SPI_FLAG_OVR) != 0UL) {
78             SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_OVR);
79             __HAL_SPI_CLEAR_OVRFLAG(hspi);
80         }
81     }
82 
83     /* SPI Mode Fault error interrupt occurred -------------------------------*/
84     if ((itflag & SPI_FLAG_MODF) != 0UL) {
85         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_MODF);
86         __HAL_SPI_CLEAR_MODFFLAG(hspi);
87     }
88 
89     /* SPI Frame error interrupt occurred ------------------------------------*/
90     if ((itflag & SPI_FLAG_FRE) != 0UL) {
91         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FRE);
92         __HAL_SPI_CLEAR_FREFLAG(hspi);
93     }
94 
95     hspi->TxXferCount = (uint16_t)0UL;
96     hspi->RxXferCount = (uint16_t)0UL;
97 }
98 
99 /**
100  * @brief  专为屏幕清屏而修改,将需要清屏的颜色批量传输
101  * @param  pData  : 要写入的数据
102  * @param  Size   : 数据大小
103  * @retval status
104  */
105 
SPI_Transmit_Ext(uint16_t pData,uint32_t Size)106 rt_err_t SPI_Transmit_Ext(uint16_t pData, uint32_t Size)
107 {
108     uint32_t tickstart;
109     uint32_t Timeout = 1000;  // 超时判断
110     uint32_t LCD_pData_32bit; // 按32位传输时的数据
111     uint32_t LCD_TxDataCount; // 传输计数
112     rt_err_t errorcode = RT_EOK;
113     SPI_HandleTypeDef *hspi = spi_handle;
114 
115     /* Check Direction parameter */
116     assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE_2LINES_TXONLY(hspi->Init.Direction));
117 
118     /* Process Locked */
119     __HAL_LOCK(hspi);
120 
121     /* Init tickstart for timeout management*/
122     tickstart = HAL_GetTick();
123 
124     if (hspi->State != HAL_SPI_STATE_READY) {
125         errorcode = -RT_EBUSY;
126         __HAL_UNLOCK(hspi);
127         return errorcode;
128     }
129 
130     if (Size == 0UL) {
131         errorcode = -RT_ERROR;
132         __HAL_UNLOCK(hspi);
133         return errorcode;
134     }
135 
136     /* Set the transaction information */
137     hspi->State     = HAL_SPI_STATE_BUSY_TX;
138     hspi->ErrorCode = HAL_SPI_ERROR_NONE;
139 
140     LCD_TxDataCount = Size;                  // 传输的数据长度
141     LCD_pData_32bit = (pData << 16) | pData; // 按32位传输时,合并2个像素点的颜色
142 
143     /*Init field not used in handle to zero */
144     hspi->pRxBuffPtr  = NULL;
145     hspi->RxXferSize  = (uint16_t)0UL;
146     hspi->RxXferCount = (uint16_t)0UL;
147     hspi->TxISR       = NULL;
148     hspi->RxISR       = NULL;
149 
150     /* Configure communication direction : 1Line */
151     if (hspi->Init.Direction == SPI_DIRECTION_1LINE) {
152         SPI_1LINE_TX(hspi);
153     }
154 
155     // 不使用硬件 TSIZE 控制,此处设置为0,即不限制传输的数据长度
156     MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, 0);
157 
158     /* Enable SPI peripheral */
159     __HAL_SPI_ENABLE(hspi);
160 
161     if (hspi->Init.Mode == SPI_MODE_MASTER) {
162         /* Master transfer start */
163         SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
164     }
165 
166     /* Transmit data in 16 Bit mode */
167     while (LCD_TxDataCount > 0UL) {
168         /* Wait until TXP flag is set to send data */
169         if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXP)) {
170             if ((hspi->TxXferCount > 1UL) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_01DATA)) {
171                 *((__IO uint32_t *)&hspi->Instance->TXDR) = (uint32_t)LCD_pData_32bit;
172                 LCD_TxDataCount -= (uint16_t)2UL;
173             } else {
174                 *((__IO uint16_t *)&hspi->Instance->TXDR) = (uint16_t)pData;
175                 LCD_TxDataCount--;
176             }
177         } else {
178             /* Timeout management */
179             if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) {
180                 /* Call standard close procedure with error check */
181                 LCD_SPI_CloseTransfer(hspi);
182 
183                 /* Process Unlocked */
184                 __HAL_UNLOCK(hspi);
185 
186                 SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
187                 hspi->State = HAL_SPI_STATE_READY;
188                 return -RT_ERROR;
189             }
190         }
191     }
192 
193     if (LCD_SPI_WaitOnFlagUntilTimeout(hspi, SPI_SR_TXC, RESET, tickstart, Timeout) != HAL_OK) {
194         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
195     }
196 
197     SET_BIT((hspi)->Instance->CR1, SPI_CR1_CSUSP); // 请求挂起SPI传输
198     /* 等待SPI挂起 */
199     if (LCD_SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_SUSP, RESET, tickstart, Timeout) != HAL_OK) {
200         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
201     }
202     LCD_SPI_CloseTransfer(hspi); /* Call standard close procedure with error check */
203 
204     SET_BIT((hspi)->Instance->IFCR, SPI_IFCR_SUSPC); // 清除挂起标志位
205 
206     /* Process Unlocked */
207     __HAL_UNLOCK(hspi);
208 
209     hspi->State = HAL_SPI_STATE_READY;
210 
211     if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) {
212         return -RT_ERROR;
213     }
214     return errorcode;
215 }
216 
217 /**
218  * @brief  专为批量写入数据修改,使之不限长度的传输数据
219  * @param  pData  : 要写入的数据
220  * @param  Size   : 数据大小
221  * @retval status
222  */
SPI_TransmitBuffer_Ext(uint16_t * pData,uint32_t Size)223 rt_err_t SPI_TransmitBuffer_Ext(uint16_t *pData, uint32_t Size)
224 {
225     uint32_t tickstart;
226     uint32_t Timeout = 1000;  // 超时判断
227     uint32_t LCD_TxDataCount; // 传输计数
228     rt_err_t errorcode = RT_EOK;
229     SPI_HandleTypeDef *hspi = spi_handle;
230 
231     /* Check Direction parameter */
232     assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE_2LINES_TXONLY(hspi->Init.Direction));
233 
234     /* Process Locked */
235     __HAL_LOCK(hspi);
236 
237     /* Init tickstart for timeout management*/
238     tickstart = HAL_GetTick();
239 
240     if (hspi->State != HAL_SPI_STATE_READY) {
241         errorcode = -RT_EBUSY;
242         __HAL_UNLOCK(hspi);
243         return errorcode;
244     }
245 
246     if (Size == 0UL) {
247         errorcode = -RT_ERROR;
248         __HAL_UNLOCK(hspi);
249         return errorcode;
250     }
251 
252     /* Set the transaction information */
253     hspi->State     = HAL_SPI_STATE_BUSY_TX;
254     hspi->ErrorCode = HAL_SPI_ERROR_NONE;
255 
256     LCD_TxDataCount = Size; // 传输的数据长度
257 
258     /*Init field not used in handle to zero */
259     hspi->pRxBuffPtr  = NULL;
260     hspi->RxXferSize  = (uint16_t)0UL;
261     hspi->RxXferCount = (uint16_t)0UL;
262     hspi->TxISR       = NULL;
263     hspi->RxISR       = NULL;
264 
265     /* Configure communication direction : 1Line */
266     if (hspi->Init.Direction == SPI_DIRECTION_1LINE) {
267         SPI_1LINE_TX(hspi);
268     }
269 
270     // 不使用硬件 TSIZE 控制,此处设置为0,即不限制传输的数据长度
271     MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, 0);
272 
273     /* Enable SPI peripheral */
274     __HAL_SPI_ENABLE(hspi);
275 
276     if (hspi->Init.Mode == SPI_MODE_MASTER) {
277         /* Master transfer start */
278         SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
279     }
280 
281     /* Transmit data in 16 Bit mode */
282     while (LCD_TxDataCount > 0UL) {
283         /* Wait until TXP flag is set to send data */
284         if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXP)) {
285             if ((LCD_TxDataCount > 1UL) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_01DATA)) {
286                 *((__IO uint32_t *)&hspi->Instance->TXDR) = *((uint32_t *)pData);
287                 pData += 2;
288                 LCD_TxDataCount -= 2;
289             } else {
290                 *((__IO uint16_t *)&hspi->Instance->TXDR) = *((uint16_t *)pData);
291                 pData += 1;
292                 LCD_TxDataCount--;
293             }
294         } else {
295             /* Timeout management */
296             if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) {
297                 /* Call standard close procedure with error check */
298                 LCD_SPI_CloseTransfer(hspi);
299 
300                 /* Process Unlocked */
301                 __HAL_UNLOCK(hspi);
302 
303                 SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
304                 hspi->State = HAL_SPI_STATE_READY;
305                 return -RT_ERROR;
306             }
307         }
308     }
309 
310     if (LCD_SPI_WaitOnFlagUntilTimeout(hspi, SPI_SR_TXC, RESET, tickstart, Timeout) != HAL_OK) {
311         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
312     }
313 
314     SET_BIT((hspi)->Instance->CR1, SPI_CR1_CSUSP); // 请求挂起SPI传输
315     /* 等待SPI挂起 */
316     if (LCD_SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_SUSP, RESET, tickstart, Timeout) != HAL_OK) {
317         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
318     }
319     LCD_SPI_CloseTransfer(hspi); /* Call standard close procedure with error check */
320 
321     SET_BIT((hspi)->Instance->IFCR, SPI_IFCR_SUSPC); // 清除挂起标志位
322 
323     /* Process Unlocked */
324     __HAL_UNLOCK(hspi);
325 
326     hspi->State = HAL_SPI_STATE_READY;
327 
328     if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) {
329         return -RT_ERROR;
330     }
331     return errorcode;
332 }
333