Skip to content

Commit 643d772

Browse files
committed
[Nuvoton] Introduce SPI_ENABLE_SYNC/SPI_DISABLE_SYNC to simplify enable/disable control
1 parent f6bcbfe commit 643d772

File tree

4 files changed

+176
-93
lines changed

4 files changed

+176
-93
lines changed

targets/TARGET_NUVOTON/TARGET_M451/spi_api.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,34 @@ static struct nu_spi_var spi2_var = {
6060
#endif
6161
};
6262

63+
/* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros
64+
*
65+
* The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI
66+
* control logic is enabled/disabled, this bit indicates the real status of SPI controller.
67+
*
68+
* NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC().
69+
* NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers,
70+
* user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0
71+
* (by SPI_DISABLE_SYNC here).
72+
*/
73+
__STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base)
74+
{
75+
if (! (spi_base->CTL & SPI_CTL_SPIEN_Msk)) {
76+
SPI_ENABLE(spi_base);
77+
}
78+
while (! (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk));
79+
}
80+
__STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base)
81+
{
82+
if (spi_base->CTL & SPI_CTL_SPIEN_Msk) {
83+
// NOTE: SPI H/W may get out of state without the busy check.
84+
while (SPI_IS_BUSY(spi_base));
85+
86+
SPI_DISABLE(spi_base);
87+
}
88+
while (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk);
89+
}
90+
6391
#if DEVICE_SPI_ASYNCH
6492
static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
6593
static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable);
@@ -177,10 +205,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
177205

178206
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
179207

180-
// NOTE 1: All configurations should be ready before enabling SPI peripheral.
181-
// NOTE 2: Re-configuration is allowed only as SPI peripheral is idle.
182-
while (SPI_IS_BUSY(spi_base));
183-
SPI_DISABLE(spi_base);
208+
SPI_DISABLE_SYNC(spi_base);
184209

185210
SPI_Open(spi_base,
186211
slave ? SPI_SLAVE : SPI_MASTER,
@@ -207,15 +232,14 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
207232
}
208233

209234
// NOTE: M451's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk). This will violate judgement of spi_active(). Disable it.
210-
SPI_DISABLE(spi_base);
235+
SPI_DISABLE_SYNC(spi_base);
211236
}
212237

213238
void spi_frequency(spi_t *obj, int hz)
214239
{
215240
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
216241

217-
while (SPI_IS_BUSY(spi_base));
218-
SPI_DISABLE(spi_base);
242+
SPI_DISABLE_SYNC(spi_base);
219243

220244
SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
221245
}
@@ -226,7 +250,7 @@ int spi_master_write(spi_t *obj, int value)
226250
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
227251

228252
// NOTE: Data in receive FIFO can be read out via ICE.
229-
SPI_ENABLE(spi_base);
253+
SPI_ENABLE_SYNC(spi_base);
230254

231255
// Wait for tx buffer empty
232256
while(! spi_writeable(obj));
@@ -236,7 +260,7 @@ int spi_master_write(spi_t *obj, int value)
236260
while (! spi_readable(obj));
237261
int value2 = SPI_READ_RX(spi_base);
238262

239-
SPI_DISABLE(spi_base);
263+
SPI_DISABLE_SYNC(spi_base);
240264

241265
return value2;
242266
}
@@ -261,7 +285,7 @@ int spi_slave_receive(spi_t *obj)
261285
{
262286
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
263287

264-
SPI_ENABLE(spi_base);
288+
SPI_ENABLE_SYNC(spi_base);
265289

266290
return spi_readable(obj);
267291
};
@@ -270,7 +294,7 @@ int spi_slave_read(spi_t *obj)
270294
{
271295
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
272296

273-
SPI_ENABLE(spi_base);
297+
SPI_ENABLE_SYNC(spi_base);
274298

275299
// Wait for rx buffer full
276300
while (! spi_readable(obj));
@@ -282,7 +306,7 @@ void spi_slave_write(spi_t *obj, int value)
282306
{
283307
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
284308

285-
SPI_ENABLE(spi_base);
309+
SPI_ENABLE_SYNC(spi_base);
286310

287311
// Wait for tx buffer empty
288312
while(! spi_writeable(obj));
@@ -316,7 +340,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
316340
spi_enable_event(obj, event, 1);
317341
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
318342

319-
SPI_ENABLE(spi_base);
343+
SPI_ENABLE_SYNC(spi_base);
320344

321345
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
322346
// Interrupt way
@@ -426,9 +450,8 @@ void spi_abort_asynch(spi_t *obj)
426450
spi_enable_vector_interrupt(obj, 0, 0);
427451
spi_master_enable_interrupt(obj, 0);
428452

429-
// FIXME: SPI H/W may get out of state without the busy check.
430-
while (SPI_IS_BUSY(spi_base));
431-
SPI_DISABLE(spi_base);
453+
/* Necessary for accessing FIFOCTL below */
454+
SPI_DISABLE_SYNC(spi_base);
432455

433456
SPI_ClearRxFIFO(spi_base);
434457
SPI_ClearTxFIFO(spi_base);

targets/TARGET_NUVOTON/TARGET_M480/spi_api.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@ static struct nu_spi_var spi4_var = {
7171
#endif
7272
};
7373

74+
/* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros
75+
*
76+
* The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI
77+
* control logic is enabled/disabled, this bit indicates the real status of SPI controller.
78+
*
79+
* NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC().
80+
* NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers,
81+
* user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0
82+
* (by SPI_DISABLE_SYNC here).
83+
*/
84+
__STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base)
85+
{
86+
if (! (spi_base->CTL & SPI_CTL_SPIEN_Msk)) {
87+
SPI_ENABLE(spi_base);
88+
}
89+
while (! (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk));
90+
}
91+
__STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base)
92+
{
93+
if (spi_base->CTL & SPI_CTL_SPIEN_Msk) {
94+
// NOTE: SPI H/W may get out of state without the busy check.
95+
while (SPI_IS_BUSY(spi_base));
96+
97+
SPI_DISABLE(spi_base);
98+
}
99+
while (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk);
100+
}
101+
74102
#if DEVICE_SPI_ASYNCH
75103
static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
76104
static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable);
@@ -184,10 +212,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
184212

185213
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
186214

187-
// NOTE 1: All configurations should be ready before enabling SPI peripheral.
188-
// NOTE 2: Re-configuration is allowed only as SPI peripheral is idle.
189-
while (SPI_IS_BUSY(spi_base));
190-
SPI_DISABLE(spi_base);
215+
SPI_DISABLE_SYNC(spi_base);
191216

192217
SPI_Open(spi_base,
193218
slave ? SPI_SLAVE : SPI_MASTER,
@@ -212,15 +237,14 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
212237
}
213238

214239
// NOTE: M451's/M480's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk). This will violate judgement of spi_active(). Disable it.
215-
SPI_DISABLE(spi_base);
240+
SPI_DISABLE_SYNC(spi_base);
216241
}
217242

218243
void spi_frequency(spi_t *obj, int hz)
219244
{
220245
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
221246

222-
while (SPI_IS_BUSY(spi_base));
223-
SPI_DISABLE(spi_base);
247+
SPI_DISABLE_SYNC(spi_base);
224248

225249
SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
226250
}
@@ -231,7 +255,7 @@ int spi_master_write(spi_t *obj, int value)
231255
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
232256

233257
// NOTE: Data in receive FIFO can be read out via ICE.
234-
SPI_ENABLE(spi_base);
258+
SPI_ENABLE_SYNC(spi_base);
235259

236260
// Wait for tx buffer empty
237261
while(! spi_writeable(obj));
@@ -241,7 +265,7 @@ int spi_master_write(spi_t *obj, int value)
241265
while (! spi_readable(obj));
242266
int value2 = SPI_READ_RX(spi_base);
243267

244-
SPI_DISABLE(spi_base);
268+
SPI_DISABLE_SYNC(spi_base);
245269

246270
return value2;
247271
}
@@ -266,7 +290,7 @@ int spi_slave_receive(spi_t *obj)
266290
{
267291
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
268292

269-
SPI_ENABLE(spi_base);
293+
SPI_ENABLE_SYNC(spi_base);
270294

271295
return spi_readable(obj);
272296
};
@@ -275,7 +299,7 @@ int spi_slave_read(spi_t *obj)
275299
{
276300
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
277301

278-
SPI_ENABLE(spi_base);
302+
SPI_ENABLE_SYNC(spi_base);
279303

280304
// Wait for rx buffer full
281305
while (! spi_readable(obj));
@@ -287,7 +311,7 @@ void spi_slave_write(spi_t *obj, int value)
287311
{
288312
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
289313

290-
SPI_ENABLE(spi_base);
314+
SPI_ENABLE_SYNC(spi_base);
291315

292316
// Wait for tx buffer empty
293317
while(! spi_writeable(obj));
@@ -320,7 +344,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
320344
spi_enable_event(obj, event, 1);
321345
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
322346

323-
SPI_ENABLE(spi_base);
347+
SPI_ENABLE_SYNC(spi_base);
324348

325349
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
326350
// Interrupt way
@@ -428,9 +452,8 @@ void spi_abort_asynch(spi_t *obj)
428452
spi_enable_vector_interrupt(obj, 0, 0);
429453
spi_master_enable_interrupt(obj, 0);
430454

431-
// NOTE: SPI H/W may get out of state without the busy check.
432-
while (SPI_IS_BUSY(spi_base));
433-
SPI_DISABLE(spi_base);
455+
/* Necessary for accessing FIFOCTL below */
456+
SPI_DISABLE_SYNC(spi_base);
434457

435458
SPI_ClearRxFIFO(spi_base);
436459
SPI_ClearTxFIFO(spi_base);

0 commit comments

Comments
 (0)