ChibiOS/HAL  6.1.0
hal_qspi.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_qspi.c
19  * @brief QSPI Driver code.
20  *
21  * @addtogroup QSPI
22  * @{
23  */
24 
25 #include "hal.h"
26 
27 #if (HAL_USE_QSPI == TRUE) || defined(__DOXYGEN__)
28 
29 /*===========================================================================*/
30 /* Driver local definitions. */
31 /*===========================================================================*/
32 
33 /*===========================================================================*/
34 /* Driver exported variables. */
35 /*===========================================================================*/
36 
37 /*===========================================================================*/
38 /* Driver local variables and types. */
39 /*===========================================================================*/
40 
41 /*===========================================================================*/
42 /* Driver local functions. */
43 /*===========================================================================*/
44 
45 /*===========================================================================*/
46 /* Driver exported functions. */
47 /*===========================================================================*/
48 
49 /**
50  * @brief QSPI Driver initialization.
51  * @note This function is implicitly invoked by @p halInit(), there is
52  * no need to explicitly initialize the driver.
53  *
54  * @init
55  */
56 void qspiInit(void) {
57 
58  qspi_lld_init();
59 }
60 
61 /**
62  * @brief Initializes the standard part of a @p QSPIDriver structure.
63  *
64  * @param[out] qspip pointer to the @p QSPIDriver object
65  *
66  * @init
67  */
68 void qspiObjectInit(QSPIDriver *qspip) {
69 
70  qspip->state = QSPI_STOP;
71  qspip->config = NULL;
72 #if QSPI_USE_WAIT == TRUE
73  qspip->thread = NULL;
74 #endif
75 #if QSPI_USE_MUTUAL_EXCLUSION == TRUE
76  osalMutexObjectInit(&qspip->mutex);
77 #endif
78 #if defined(QSPI_DRIVER_EXT_INIT_HOOK)
79  QSPI_DRIVER_EXT_INIT_HOOK(qspip);
80 #endif
81 }
82 
83 /**
84  * @brief Configures and activates the QSPI peripheral.
85  *
86  * @param[in] qspip pointer to the @p QSPIDriver object
87  * @param[in] config pointer to the @p QSPIConfig object
88  *
89  * @api
90  */
91 void qspiStart(QSPIDriver *qspip, const QSPIConfig *config) {
92 
93  osalDbgCheck((qspip != NULL) && (config != NULL));
94 
95  osalSysLock();
96 
97  osalDbgAssert((qspip->state == QSPI_STOP) || (qspip->state == QSPI_READY),
98  "invalid state");
99 
100  qspip->config = config;
101  qspi_lld_start(qspip);
102  qspip->state = QSPI_READY;
103 
104  osalSysUnlock();
105 }
106 
107 /**
108  * @brief Deactivates the QSPI peripheral.
109  * @note Deactivating the peripheral also enforces a release of the slave
110  * select line.
111  *
112  * @param[in] qspip pointer to the @p QSPIDriver object
113  *
114  * @api
115  */
116 void qspiStop(QSPIDriver *qspip) {
117 
118  osalDbgCheck(qspip != NULL);
119 
120  osalSysLock();
121 
122  osalDbgAssert((qspip->state == QSPI_STOP) || (qspip->state == QSPI_READY),
123  "invalid state");
124 
125  qspi_lld_stop(qspip);
126  qspip->config = NULL;
127  qspip->state = QSPI_STOP;
128 
129  osalSysUnlock();
130 }
131 
132 /**
133  * @brief Sends a command without data phase.
134  * @post At the end of the operation the configured callback is invoked.
135  *
136  * @param[in] qspip pointer to the @p QSPIDriver object
137  * @param[in] cmdp pointer to the command descriptor
138  *
139  * @api
140  */
141 void qspiStartCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) {
142 
143  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
144 
145  osalSysLock();
146 
147  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
148 
149  qspiStartCommandI(qspip, cmdp);
150 
151  osalSysUnlock();
152 }
153 
154 /**
155  * @brief Sends a command with data over the QSPI bus.
156  * @post At the end of the operation the configured callback is invoked.
157  *
158  * @param[in] qspip pointer to the @p QSPIDriver object
159  * @param[in] cmdp pointer to the command descriptor
160  * @param[in] n number of bytes to send
161  * @param[in] txbuf the pointer to the transmit buffer
162  *
163  * @api
164  */
165 void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
166  size_t n, const uint8_t *txbuf) {
167 
168  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
169  osalDbgCheck((n > 0U) && (txbuf != NULL));
170 
171  osalSysLock();
172 
173  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
174 
175  qspiStartSendI(qspip, cmdp, n, txbuf);
176 
177  osalSysUnlock();
178 }
179 
180 /**
181  * @brief Sends a command then receives data over the QSPI bus.
182  * @post At the end of the operation the configured callback is invoked.
183  *
184  * @param[in] qspip pointer to the @p QSPIDriver object
185  * @param[in] cmdp pointer to the command descriptor
186  * @param[in] n number of bytes to send
187  * @param[out] rxbuf the pointer to the receive buffer
188  *
189  * @api
190  */
191 void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
192  size_t n, uint8_t *rxbuf) {
193 
194  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
195  osalDbgCheck((n > 0U) && (rxbuf != NULL));
196 
197  osalSysLock();
198 
199  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
200 
201  qspiStartReceiveI(qspip, cmdp, n, rxbuf);
202 
203  osalSysUnlock();
204 }
205 
206 #if (QSPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
207 /**
208  * @brief Sends a command without data phase.
209  * @pre In order to use this function the option @p QSPI_USE_WAIT must be
210  * enabled.
211  * @pre In order to use this function the driver must have been configured
212  * without callbacks (@p end_cb = @p NULL).
213  *
214  * @param[in] qspip pointer to the @p QSPIDriver object
215  * @param[in] cmdp pointer to the command descriptor
216  *
217  * @api
218  */
219 void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) {
220 
221  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
222  osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) == QSPI_CFG_DATA_MODE_NONE);
223 
224  osalSysLock();
225 
226  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
227  osalDbgAssert(qspip->config->end_cb == NULL, "has callback");
228 
229  qspiStartCommandI(qspip, cmdp);
230  (void) osalThreadSuspendS(&qspip->thread);
231 
232  osalSysUnlock();
233 }
234 
235 /**
236  * @brief Sends a command with data over the QSPI bus.
237  * @pre In order to use this function the option @p QSPI_USE_WAIT must be
238  * enabled.
239  * @pre In order to use this function the driver must have been configured
240  * without callbacks (@p end_cb = @p NULL).
241  *
242  * @param[in] qspip pointer to the @p QSPIDriver object
243  * @param[in] cmdp pointer to the command descriptor
244  * @param[in] n number of bytes to send
245  * @param[in] txbuf the pointer to the transmit buffer
246  *
247  * @api
248  */
249 void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
250  size_t n, const uint8_t *txbuf) {
251 
252  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
253  osalDbgCheck((n > 0U) && (txbuf != NULL));
254  osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) != QSPI_CFG_DATA_MODE_NONE);
255 
256  osalSysLock();
257 
258  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
259  osalDbgAssert(qspip->config->end_cb == NULL, "has callback");
260 
261  qspiStartSendI(qspip, cmdp, n, txbuf);
262  (void) osalThreadSuspendS(&qspip->thread);
263 
264  osalSysUnlock();
265 }
266 
267 /**
268  * @brief Sends a command then receives data over the QSPI bus.
269  * @pre In order to use this function the option @p QSPI_USE_WAIT must be
270  * enabled.
271  * @pre In order to use this function the driver must have been configured
272  * without callbacks (@p end_cb = @p NULL).
273  *
274  * @param[in] qspip pointer to the @p QSPIDriver object
275  * @param[in] cmdp pointer to the command descriptor
276  * @param[in] n number of bytes to send
277  * @param[out] rxbuf the pointer to the receive buffer
278  *
279  * @api
280  */
281 void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
282  size_t n, uint8_t *rxbuf) {
283 
284  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
285  osalDbgCheck((n > 0U) && (rxbuf != NULL));
286  osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) != QSPI_CFG_DATA_MODE_NONE);
287 
288  osalSysLock();
289 
290  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
291  osalDbgAssert(qspip->config->end_cb == NULL, "has callback");
292 
293  qspiStartReceiveI(qspip, cmdp, n, rxbuf);
294  (void) osalThreadSuspendS(&qspip->thread);
295 
296  osalSysUnlock();
297 }
298 #endif /* QSPI_USE_WAIT == TRUE */
299 
300 #if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
301 /**
302  * @brief Maps in memory space a QSPI flash device.
303  * @pre The memory flash device must be initialized appropriately
304  * before mapping it in memory space.
305  *
306  * @param[in] qspip pointer to the @p QSPIDriver object
307  * @param[in] cmdp pointer to the command descriptor
308  * @param[out] addrp pointer to the memory start address of the mapped
309  * flash or @p NULL
310  *
311  * @api
312  */
314  const qspi_command_t *cmdp,
315  uint8_t **addrp) {
316 
317  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
318  osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) != QSPI_CFG_DATA_MODE_NONE);
319 
320  osalSysLock();
321 
322  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
323 
324  qspiMapFlashI(qspip, cmdp, addrp);
325  qspip->state = QSPI_MEMMAP;
326 
327  osalSysUnlock();
328 }
329 
330 /**
331  * @brief Unmaps from memory space a QSPI flash device.
332  * @post The memory flash device must be re-initialized for normal
333  * commands exchange.
334  *
335  * @param[in] qspip pointer to the @p QSPIDriver object
336  *
337  * @api
338  */
340 
341  osalDbgCheck(qspip != NULL);
342 
343  osalSysLock();
344 
345  osalDbgAssert(qspip->state == QSPI_MEMMAP, "not ready");
346 
347  qspiUnmapFlashI(qspip);
348  qspip->state = QSPI_READY;
349 
350  osalSysUnlock();
351 }
352 #endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
353 
354 #if (QSPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
355 /**
356  * @brief Gains exclusive access to the QSPI bus.
357  * @details This function tries to gain ownership to the QSPI bus, if the bus
358  * is already being used then the invoking thread is queued.
359  * @pre In order to use this function the option @p QSPI_USE_MUTUAL_EXCLUSION
360  * must be enabled.
361  *
362  * @param[in] qspip pointer to the @p QSPIDriver object
363  *
364  * @api
365  */
367 
368  osalDbgCheck(qspip != NULL);
369 
370  osalMutexLock(&qspip->mutex);
371 }
372 
373 /**
374  * @brief Releases exclusive access to the QSPI bus.
375  * @pre In order to use this function the option @p QSPI_USE_MUTUAL_EXCLUSION
376  * must be enabled.
377  *
378  * @param[in] qspip pointer to the @p QSPIDriver object
379  *
380  * @api
381  */
383 
384  osalDbgCheck(qspip != NULL);
385 
386  osalMutexUnlock(&qspip->mutex);
387 }
388 #endif /* QSPI_USE_MUTUAL_EXCLUSION == TRUE */
389 
390 #endif /* HAL_USE_QSPI == TRUE */
391 
392 /** @} */
static void osalMutexObjectInit(mutex_t *mp)
Initializes s mutex_t object.
Definition: osal.h:681
qspistate_t state
Driver state.
Definition: hal_qspi_lld.h:98
#define qspiStartReceiveI(qspip, cmdp, n, rxbuf)
Receives data from the QSPI bus.
Definition: hal_qspi.h:194
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition: osal.c:185
void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf)
Sends a command with data over the QSPI bus.
Definition: hal_qspi.c:165
void qspiUnmapFlash(QSPIDriver *qspip)
Unmaps from memory space a QSPI flash device.
Definition: hal_qspi.c:339
qspicallback_t end_cb
Operation complete callback or NULL.
Definition: hal_qspi_lld.h:87
void qspiObjectInit(QSPIDriver *qspip)
Initializes the standard part of a QSPIDriver structure.
Definition: hal_qspi.c:68
void qspiReleaseBus(QSPIDriver *qspip)
Releases exclusive access to the QSPI bus.
Definition: hal_qspi.c:382
HAL subsystem header.
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition: osal.c:384
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:540
void qspi_lld_init(void)
Low level QSPI driver initialization.
Definition: hal_qspi_lld.c:63
Driver configuration structure.
Definition: hal_qspi_lld.h:83
void qspiStartCommand(QSPIDriver *qspip, const qspi_command_t *cmdp)
Sends a command without data phase.
Definition: hal_qspi.c:141
void qspiStart(QSPIDriver *qspip, const QSPIConfig *config)
Configures and activates the QSPI peripheral.
Definition: hal_qspi.c:91
void qspi_lld_start(QSPIDriver *qspip)
Configures and activates the QSPI peripheral.
Definition: hal_qspi_lld.c:77
void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf)
Sends a command then receives data over the QSPI bus.
Definition: hal_qspi.c:281
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf)
Sends a command then receives data over the QSPI bus.
Definition: hal_qspi.c:191
const QSPIConfig * config
Current configuration data.
Definition: hal_qspi_lld.h:102
mutex_t mutex
Mutex protecting the peripheral.
Definition: hal_qspi_lld.h:113
void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf)
Sends a command with data over the QSPI bus.
Definition: hal_qspi.c:249
void qspiAcquireBus(QSPIDriver *qspip)
Gains exclusive access to the QSPI bus.
Definition: hal_qspi.c:366
thread_reference_t thread
Waiting thread.
Definition: hal_qspi_lld.h:107
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:530
Structure representing an QSPI driver.
Definition: hal_qspi_lld.h:94
#define qspiUnmapFlashI(qspip)
Maps in memory space a QSPI flash device.
Definition: hal_qspi.h:227
void qspi_lld_stop(QSPIDriver *qspip)
Deactivates the QSPI peripheral.
Definition: hal_qspi_lld.c:99
void qspiMapFlash(QSPIDriver *qspip, const qspi_command_t *cmdp, uint8_t **addrp)
Maps in memory space a QSPI flash device.
Definition: hal_qspi.c:313
void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp)
Sends a command without data phase.
Definition: hal_qspi.c:219
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition: osal.c:404
#define qspiMapFlashI(qspip, cmdp, addrp)
Maps in memory space a QSPI flash device.
Definition: hal_qspi.h:215
#define qspiStartSendI(qspip, cmdp, n, txbuf)
Sends data over the QSPI bus.
Definition: hal_qspi.h:174
void qspiStop(QSPIDriver *qspip)
Deactivates the QSPI peripheral.
Definition: hal_qspi.c:116
void qspiInit(void)
QSPI Driver initialization.
Definition: hal_qspi.c:56
Type of a QSPI command descriptor.
Definition: hal_qspi.h:125
#define qspiStartCommandI(qspip, cmdp)
Sends a command without data phase.
Definition: hal_qspi.h:154