@@ -87,10 +87,10 @@ static IRQn_Type spi_irq_allocate_channel(spi_obj_t *obj)
87
87
#endif // M0
88
88
}
89
89
90
- static void spi_irq_release_channel (IRQn_Type channel , uint32_t spi_id )
90
+ static void spi_irq_release_channel (spi_obj_t * obj )
91
91
{
92
92
#if defined (TARGET_MCU_PSOC6_M0 )
93
- cy_m0_nvic_release_channel (channel , CY_SERIAL_IRQN_ID + spi_id );
93
+ cy_m0_nvic_release_channel (obj -> irqn , CY_SERIAL_IRQN_ID + obj -> spi_id );
94
94
#endif //M0
95
95
}
96
96
@@ -130,6 +130,14 @@ static int allocate_divider(spi_obj_t *obj)
130
130
return (obj -> div_num == CY_INVALID_DIVIDER )? -1 : 0 ;
131
131
}
132
132
133
+ static void free_divider (spi_obj_t * obj )
134
+ {
135
+ if (obj -> div_num != CY_INVALID_DIVIDER ) {
136
+ cy_clk_free_divider (obj -> div_type , obj -> div_num );
137
+ obj -> div_num = CY_INVALID_DIVIDER ;
138
+ }
139
+ }
140
+
133
141
134
142
/*
135
143
* Initializes spi clock for the required speed
@@ -149,6 +157,8 @@ static cy_en_sysclk_status_t spi_init_clock(spi_obj_t *obj, uint32_t frequency)
149
157
// Set up proper frequency; round up the divider so the frequency is not higher than specified.
150
158
div_value = (CY_CLK_PERICLK_FREQ_HZ + frequency * (SPI_OVERSAMPLE - 1 )) / frequency / SPI_OVERSAMPLE ;
151
159
obj -> clk_frequency = CY_CLK_PERICLK_FREQ_HZ / div_value / SPI_OVERSAMPLE ;
160
+ // Delay (in us) required for serialized read operation == 1.5 clocks, min 1us.
161
+ obj -> clk_delay = (1500000UL - 1 + obj -> clk_frequency ) / obj -> clk_frequency ;
152
162
Cy_SysClk_PeriphDisableDivider (obj -> div_type , obj -> div_num );
153
163
if (Cy_SysClk_PeriphSetDivider (obj -> div_type , obj -> div_num , div_value ) != CY_SYSCLK_SUCCESS ) {
154
164
obj -> div_num = CY_INVALID_DIVIDER ;
@@ -165,48 +175,77 @@ static cy_en_sysclk_status_t spi_init_clock(spi_obj_t *obj, uint32_t frequency)
165
175
return CY_SYSCLK_SUCCESS ;
166
176
}
167
177
178
+ /*
179
+ * Sets up i/o connections for spi.
180
+ */
181
+ static void spi_set_pins (spi_obj_t * obj )
182
+ {
183
+ if (obj -> pin_mosi != NC ) {
184
+ pin_function (obj -> pin_mosi , pinmap_function (obj -> pin_mosi , PinMap_SPI_MOSI ));
185
+ }
186
+ if (obj -> pin_miso != NC ) {
187
+ pin_function (obj -> pin_miso , pinmap_function (obj -> pin_miso , PinMap_SPI_MISO ));
188
+ }
189
+ if (obj -> pin_ssel != NC ) {
190
+ pin_function (obj -> pin_ssel , pinmap_function (obj -> pin_ssel , PinMap_SPI_SSEL ));
191
+ }
192
+ pin_function (obj -> pin_sclk , pinmap_function (obj -> pin_sclk , PinMap_SPI_SCLK ));
193
+ // Pin configuration in PinMap defaults to Master mode; revert for Slave.
194
+ if (obj -> ms_mode == CY_SCB_SPI_SLAVE ) {
195
+ pin_mode (obj -> pin_sclk , PullNone );
196
+ pin_mode (obj -> pin_mosi , PullNone );
197
+ pin_mode (obj -> pin_miso , PushPull );
198
+ pin_mode (obj -> pin_ssel , PullNone );
199
+ }
200
+ }
201
+
202
+ /*
203
+ * Sets i/o output pins into safe mode while re-configuring peripheral.
204
+ */
205
+ static void spi_default_pins (spi_obj_t * obj )
206
+ {
207
+
208
+ if (obj -> ms_mode == CY_SCB_SPI_MASTER ) {
209
+ pin_function (obj -> pin_sclk , CY_PIN_FUNCTION (HSIOM_SEL_GPIO , 0 , PullDown , PIN_OUTPUT ));
210
+ if (obj -> pin_mosi != NC ) {
211
+ pin_function (obj -> pin_mosi , CY_PIN_FUNCTION (HSIOM_SEL_GPIO , 0 , PullUp , PIN_OUTPUT ));
212
+ }
213
+ if (obj -> pin_ssel != NC ) {
214
+ pin_function (obj -> pin_ssel , CY_PIN_FUNCTION (HSIOM_SEL_GPIO , 0 , PullUp , PIN_OUTPUT ));
215
+ }
216
+ } else {
217
+ if (obj -> pin_miso != NC ) {
218
+ pin_function (obj -> pin_miso , CY_PIN_FUNCTION (HSIOM_SEL_GPIO , 0 , PullUp , PIN_OUTPUT ));
219
+ }
220
+ }
221
+ }
222
+
168
223
/*
169
224
* Initializes i/o pins for spi.
170
225
*/
171
226
static void spi_init_pins (spi_obj_t * obj )
172
227
{
173
228
bool conflict = false;
174
229
conflict = cy_reserve_io_pin (obj -> pin_sclk );
175
- if (!conflict ) {
176
- pin_function (obj -> pin_sclk , pinmap_function (obj -> pin_sclk , PinMap_SPI_SCLK ));
177
- }
178
230
if (obj -> pin_mosi != NC ) {
179
- if (!cy_reserve_io_pin (obj -> pin_mosi )) {
180
- pin_function (obj -> pin_mosi , pinmap_function (obj -> pin_mosi , PinMap_SPI_MOSI ));
181
- } else {
231
+ if (cy_reserve_io_pin (obj -> pin_mosi )) {
182
232
conflict = true;
183
233
}
184
234
}
185
235
if (obj -> pin_miso != NC ) {
186
- if (!cy_reserve_io_pin (obj -> pin_miso )) {
187
- pin_function (obj -> pin_miso , pinmap_function (obj -> pin_miso , PinMap_SPI_MISO ));
188
- } else {
236
+ if (cy_reserve_io_pin (obj -> pin_miso )) {
189
237
conflict = true;
190
238
}
191
239
}
192
240
if (obj -> pin_ssel != NC ) {
193
- if (!cy_reserve_io_pin (obj -> pin_ssel )) {
194
- pin_function (obj -> pin_ssel , pinmap_function (obj -> pin_ssel , PinMap_SPI_SSEL ));
195
- } else {
241
+ if (cy_reserve_io_pin (obj -> pin_ssel )) {
196
242
conflict = true;
197
243
}
198
244
}
199
245
if (conflict ) {
200
246
error ("SPI pin reservation conflict." );
201
247
}
202
-
203
- // Pin configuration in PinMap defaults to Master mode; revert for Slave.
204
- if (obj -> ms_mode == CY_SCB_SPI_SLAVE ) {
205
- pin_mode (obj -> pin_sclk , PullNone );
206
- pin_mode (obj -> pin_mosi , PullNone );
207
- pin_mode (obj -> pin_miso , PushPull );
208
- pin_mode (obj -> pin_ssel , PullNone );
209
- }
248
+ spi_set_pins (obj );
210
249
}
211
250
212
251
/*
@@ -282,8 +321,8 @@ void spi_init(spi_t *obj_in, PinName mosi, PinName miso, PinName sclk, PinName s
282
321
obj -> rx_buffer_size = 0 ;
283
322
#endif // DEVICE_SPI_ASYNCH
284
323
spi_init_clock (obj , SPI_DEFAULT_SPEED );
285
- spi_init_pins (obj );
286
324
spi_init_peripheral (obj );
325
+ spi_init_pins (obj );
287
326
#if DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
288
327
obj -> pm_callback_handler .callback = spi_pm_callback ;
289
328
obj -> pm_callback_handler .type = CY_SYSPM_DEEPSLEEP ;
@@ -300,27 +339,73 @@ void spi_init(spi_t *obj_in, PinName mosi, PinName miso, PinName sclk, PinName s
300
339
}
301
340
}
302
341
342
+
343
+ void spi_free (spi_t * obj_in )
344
+ {
345
+ spi_obj_t * obj = OBJ_P (obj_in );
346
+
347
+ spi_default_pins (obj );
348
+ Cy_SCB_SPI_Disable (obj -> base , & obj -> context );
349
+ Cy_SCB_SPI_DeInit (obj -> base );
350
+
351
+ #if DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
352
+ Cy_SysPm_UnregisterCallback (& obj -> pm_callback_handler );
353
+ #endif // DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
354
+
355
+ #if DEVICE_SPI_ASYNCH
356
+ if (obj -> irqn != unconnected_IRQn ) {
357
+ NVIC_DisableIRQ (obj -> irqn );
358
+ spi_irq_release_channel (obj );
359
+
360
+ obj -> irqn = unconnected_IRQn ;
361
+ }
362
+ #endif // DEVICE_SPI_ASYNCH
363
+
364
+ if (obj -> pin_sclk != NC ) {
365
+ cy_free_io_pin (obj -> pin_sclk );
366
+ obj -> pin_sclk = NC ;
367
+ }
368
+ if (obj -> pin_mosi != NC ) {
369
+ cy_free_io_pin (obj -> pin_mosi );
370
+ obj -> pin_mosi = NC ;
371
+ }
372
+ if (obj -> pin_miso != NC ) {
373
+ cy_free_io_pin (obj -> pin_miso );
374
+ obj -> pin_miso = NC ;
375
+ }
376
+ if (obj -> pin_ssel != NC ) {
377
+ cy_free_io_pin (obj -> pin_ssel );
378
+ obj -> pin_ssel = NC ;
379
+ }
380
+
381
+ free_divider (obj );
382
+ }
383
+
384
+
303
385
void spi_format (spi_t * obj_in , int bits , int mode , int slave )
304
386
{
305
387
spi_obj_t * obj = OBJ_P (obj_in );
306
388
cy_en_scb_spi_mode_t new_mode = slave ? CY_SCB_SPI_SLAVE : CY_SCB_SPI_MASTER ;
307
389
if ((bits < 4 ) || (bits > 16 )) return ;
390
+ spi_default_pins (obj );
308
391
Cy_SCB_SPI_Disable (obj -> base , & obj -> context );
309
392
obj -> data_bits = bits ;
310
393
obj -> clk_mode = (cy_en_scb_spi_sclk_mode_t )(mode & 0x3 );
311
394
if (obj -> ms_mode != new_mode ) {
312
395
obj -> ms_mode = new_mode ;
313
- spi_init_pins (obj );
314
396
}
315
397
spi_init_peripheral (obj );
398
+ spi_set_pins (obj );
316
399
}
317
400
318
401
void spi_frequency (spi_t * obj_in , int hz )
319
402
{
320
403
spi_obj_t * obj = OBJ_P (obj_in );
404
+ spi_default_pins (obj );
321
405
Cy_SCB_SPI_Disable (obj -> base , & obj -> context );
322
406
spi_init_clock (obj , hz );
323
407
Cy_SCB_SPI_Enable (obj -> base );
408
+ spi_set_pins (obj );
324
409
}
325
410
326
411
int spi_master_write (spi_t * obj_in , int value )
@@ -335,6 +420,10 @@ int spi_master_write(spi_t *obj_in, int value)
335
420
while (!Cy_SCB_SPI_IsTxComplete (obj -> base )) {
336
421
// wait for the transmission to complete
337
422
}
423
+ // Wait until RX FIFO is filled from the serial register.
424
+ while (Cy_SCB_SPI_GetNumInRxFifo (obj -> base ) == 0 ) {
425
+ /* busy loop */
426
+ }
338
427
return Cy_SCB_SPI_Read (obj -> base );
339
428
} else {
340
429
return (int )CY_SCB_SPI_RX_NO_DATA ;
@@ -387,6 +476,9 @@ int spi_master_block_write(spi_t *obj_in, const char *tx_buffer, int tx_length,
387
476
++ rx_count ;
388
477
}
389
478
}
479
+ // Delay at least 1.5 clock cycle, so that FIFO is filled with the last char
480
+ // and SCLK returns to idle state.
481
+ Cy_SysLib_DelayUs (obj -> clk_delay );
390
482
// Read any remaining bytes from the fifo.
391
483
while (rx_count < rx_length ) {
392
484
* rx_buffer ++ = (char )Cy_SCB_SPI_Read (obj -> base );
0 commit comments