SAM4SD32 (SAM4S-EK2)
Loading...
Searching...
No Matches
spi.c
Go to the documentation of this file.
1
33/*
34 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
35 */
36
37#include "spi.h"
38#include "sysclk.h"
39
51#ifndef SPI_WPMR_WPKEY_PASSWD
52#define SPI_WPMR_WPKEY_PASSWD SPI_WPMR_WPKEY((uint32_t) 0x535049)
53#endif
54
61{
62#if (SAM4S || SAM3S || SAM3N || SAM3U || SAM4E || SAM4N || SAMG51|| SAMG53|| SAMG54)
63 UNUSED(p_spi);
64 sysclk_enable_peripheral_clock(ID_SPI);
65#elif (SAM3XA || SAM4C || SAM4CP || SAM4CM || SAMV71 || SAMV70 || SAME70 || SAMS70)
66 if (p_spi == SPI0) {
67 sysclk_enable_peripheral_clock(ID_SPI0);
68 }
69 #ifdef SPI1
70 else if (p_spi == SPI1) {
71 sysclk_enable_peripheral_clock(ID_SPI1);
72 }
73 #endif
74#elif (SAMG55)
75 if (p_spi == SPI0) {
76 sysclk_enable_peripheral_clock(ID_FLEXCOM0);
77 }
78 #ifdef SPI1
79 else if (p_spi == SPI1) {
80 sysclk_enable_peripheral_clock(ID_FLEXCOM1);
81 }
82 #endif
83 #ifdef SPI2
84 else if (p_spi == SPI2) {
85 sysclk_enable_peripheral_clock(ID_FLEXCOM2);
86 }
87 #endif
88 #ifdef SPI3
89 else if (p_spi == SPI3) {
90 sysclk_enable_peripheral_clock(ID_FLEXCOM3);
91 }
92 #endif
93 #ifdef SPI4
94 else if (p_spi == SPI4) {
95 sysclk_enable_peripheral_clock(ID_FLEXCOM4);
96 }
97 #endif
98 #ifdef SPI5
99 else if (p_spi == SPI5) {
100 sysclk_enable_peripheral_clock(ID_FLEXCOM5);
101 }
102 #endif
103 #ifdef SPI6
104 else if (p_spi == SPI6) {
105 sysclk_enable_peripheral_clock(ID_FLEXCOM6);
106 }
107 #endif
108 #ifdef SPI7
109 else if (p_spi == SPI7) {
110 sysclk_enable_peripheral_clock(ID_FLEXCOM7);
111 }
112 #endif
113#elif SAM4L
114 sysclk_enable_peripheral_clock(p_spi);
115#endif
116}
117
124{
125#if (SAM4S || SAM3S || SAM3N || SAM3U || SAM4E || SAM4N || SAMG51|| SAMG53|| SAMG54)
126 UNUSED(p_spi);
127 sysclk_disable_peripheral_clock(ID_SPI);
128#elif (SAM3XA || SAM4C || SAM4CP || SAM4CM || SAMV71 || SAMV70 || SAME70 || SAMS70)
129 if (p_spi == SPI0) {
130 sysclk_disable_peripheral_clock(ID_SPI0);
131 }
132 #ifdef SPI1
133 else if (p_spi == SPI1) {
134 sysclk_disable_peripheral_clock(ID_SPI1);
135 }
136 #endif
137#elif (SAMG55)
138 if (p_spi == SPI0) {
139 sysclk_disable_peripheral_clock(ID_FLEXCOM0);
140 }
141 #ifdef SPI1
142 else if (p_spi == SPI1) {
143 sysclk_disable_peripheral_clock(ID_FLEXCOM1);
144 }
145 #endif
146 #ifdef SPI2
147 else if (p_spi == SPI2) {
148 sysclk_disable_peripheral_clock(ID_FLEXCOM2);
149 }
150 #endif
151 #ifdef SPI3
152 else if (p_spi == SPI3) {
153 sysclk_disable_peripheral_clock(ID_FLEXCOM3);
154 }
155 #endif
156 #ifdef SPI4
157 else if (p_spi == SPI4) {
158 sysclk_disable_peripheral_clock(ID_FLEXCOM4);
159 }
160 #endif
161 #ifdef SPI5
162 else if (p_spi == SPI5) {
163 sysclk_disable_peripheral_clock(ID_FLEXCOM5);
164 }
165 #endif
166 #ifdef SPI6
167 else if (p_spi == SPI6) {
168 sysclk_disable_peripheral_clock(ID_FLEXCOM6);
169 }
170 #endif
171 #ifdef SPI7
172 else if (p_spi == SPI7) {
173 sysclk_disable_peripheral_clock(ID_FLEXCOM7);
174 }
175 #endif
176#elif SAM4L
177 sysclk_disable_peripheral_clock(p_spi);
178#endif
179}
180
193void spi_set_peripheral_chip_select_value(Spi *p_spi, uint32_t ul_value)
194{
195 p_spi->SPI_MR &= (~SPI_MR_PCS_Msk);
196 p_spi->SPI_MR |= SPI_MR_PCS(ul_value);
197}
198
206void spi_set_delay_between_chip_select(Spi *p_spi, uint32_t ul_delay)
207{
208 p_spi->SPI_MR &= (~SPI_MR_DLYBCS_Msk);
209 p_spi->SPI_MR |= SPI_MR_DLYBCS(ul_delay);
210}
211
224spi_status_t spi_read(Spi *p_spi, uint16_t *us_data, uint8_t *p_pcs)
225{
226 uint32_t timeout = SPI_TIMEOUT;
227 static uint32_t reg_value;
228
229 while (!(p_spi->SPI_SR & SPI_SR_RDRF)) {
230 if (!timeout--) {
231 return SPI_ERROR_TIMEOUT;
232 }
233 }
234
235 reg_value = p_spi->SPI_RDR;
237 *p_pcs = (uint8_t) ((reg_value & SPI_RDR_PCS_Msk) >> SPI_RDR_PCS_Pos);
238 }
239 *us_data = (uint16_t) (reg_value & SPI_RDR_RD_Msk);
240
241 return SPI_OK;
242}
243
257spi_status_t spi_write(Spi *p_spi, uint16_t us_data,
258 uint8_t uc_pcs, uint8_t uc_last)
259{
260 uint32_t timeout = SPI_TIMEOUT;
261 uint32_t value;
262
263 while (!(p_spi->SPI_SR & SPI_SR_TDRE)) {
264 if (!timeout--) {
265 return SPI_ERROR_TIMEOUT;
266 }
267 }
268
270 value = SPI_TDR_TD(us_data) | SPI_TDR_PCS(uc_pcs);
271 if (uc_last) {
272 value |= SPI_TDR_LASTXFER;
273 }
274 } else {
275 value = SPI_TDR_TD(us_data);
276 }
277
278 p_spi->SPI_TDR = value;
279
280 return SPI_OK;
281}
282
290void spi_set_clock_polarity(Spi *p_spi, uint32_t ul_pcs_ch,
291 uint32_t ul_polarity)
292{
293 if (ul_polarity) {
294 p_spi->SPI_CSR[ul_pcs_ch] |= SPI_CSR_CPOL;
295 } else {
296 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_CPOL);
297 }
298}
299
307void spi_set_clock_phase(Spi *p_spi, uint32_t ul_pcs_ch, uint32_t ul_phase)
308{
309 if (ul_phase) {
310 p_spi->SPI_CSR[ul_pcs_ch] |= SPI_CSR_NCPHA;
311 } else {
312 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_NCPHA);
313 }
314}
315
323void spi_configure_cs_behavior(Spi *p_spi, uint32_t ul_pcs_ch,
324 uint32_t ul_cs_behavior)
325{
326 if (ul_cs_behavior == SPI_CS_RISE_FORCED) {
327 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_CSAAT);
328 p_spi->SPI_CSR[ul_pcs_ch] |= SPI_CSR_CSNAAT;
329 } else if (ul_cs_behavior == SPI_CS_RISE_NO_TX) {
330 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_CSAAT);
331 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_CSNAAT);
332 } else if (ul_cs_behavior == SPI_CS_KEEP_LOW) {
333 p_spi->SPI_CSR[ul_pcs_ch] |= SPI_CSR_CSAAT;
334 }
335}
336
345void spi_set_bits_per_transfer(Spi *p_spi, uint32_t ul_pcs_ch,
346 uint32_t ul_bits)
347{
348 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_BITS_Msk);
349 p_spi->SPI_CSR[ul_pcs_ch] |= ul_bits;
350}
351
362int16_t spi_calc_baudrate_div(const uint32_t baudrate, uint32_t mck)
363{
364 int baud_div = div_ceil(mck, baudrate);
365
366 /* The value of baud_div is from 1 to 255 in the SCBR field. */
367 if (baud_div <= 0 || baud_div > 255) {
368 return -1;
369 }
370
371 return baud_div;
372}
373
385int16_t spi_set_baudrate_div(Spi *p_spi, uint32_t ul_pcs_ch,
386 uint8_t uc_baudrate_divider)
387{
388 /* Programming the SCBR field to 0 is forbidden */
389 if (!uc_baudrate_divider){
390 return -1;
391 }
392 p_spi->SPI_CSR[ul_pcs_ch] &= (~SPI_CSR_SCBR_Msk);
393 p_spi->SPI_CSR[ul_pcs_ch] |= SPI_CSR_SCBR(uc_baudrate_divider);
394 return 0;
395}
396
405void spi_set_transfer_delay(Spi *p_spi, uint32_t ul_pcs_ch,
406 uint8_t uc_dlybs, uint8_t uc_dlybct)
407{
408 p_spi->SPI_CSR[ul_pcs_ch] &= ~(SPI_CSR_DLYBS_Msk | SPI_CSR_DLYBCT_Msk);
409 p_spi->SPI_CSR[ul_pcs_ch] |= SPI_CSR_DLYBS(uc_dlybs)
410 | SPI_CSR_DLYBCT(uc_dlybct);
411}
412
413
420void spi_set_writeprotect(Spi *p_spi, uint32_t ul_enable)
421{
422#if SAM4L
423 if (ul_enable) {
424 p_spi->SPI_WPCR = SPI_WPCR_SPIWPKEY_VALUE | SPI_WPCR_SPIWPEN;
425 } else {
426 p_spi->SPI_WPCR = SPI_WPCR_SPIWPKEY_VALUE;
427 }
428#else
429 if (ul_enable) {
431 } else {
433 }
434#endif
435}
436
445{
446 return p_spi->SPI_WPSR;
447}
448
#define SPI_RDR_RD_Msk
(SPI_RDR) Receive Data
#define SPI_MR_PCS_Msk
(SPI_MR) Peripheral Chip Select
#define SPI_RDR_PCS_Msk
(SPI_RDR) Peripheral Chip Select
#define SPI_CSR_SCBR_Msk
(SPI_CSR[4]) Serial Clock Baud Rate
#define SPI_MR_DLYBCS(value)
#define SPI_CSR_DLYBS(value)
#define SPI_RDR_PCS_Pos
#define SPI_TDR_LASTXFER
(SPI_TDR) Last Transfer
#define SPI_TDR_TD(value)
#define SPI_CSR_SCBR(value)
#define SPI_MR_PCS(value)
#define SPI_CSR_DLYBCT(value)
#define SPI_SR_TDRE
(SPI_SR) Transmit Data Register Empty
#define SPI_MR_DLYBCS_Msk
(SPI_MR) Delay Between Chip Selects
#define SPI_CSR_BITS_Msk
(SPI_CSR[4]) Bits Per Transfer
#define SPI_CSR_DLYBS_Msk
(SPI_CSR[4]) Delay Before SPCK
#define SPI_CSR_CPOL
(SPI_CSR[4]) Clock Polarity
#define SPI_CSR_CSAAT
(SPI_CSR[4]) Chip Select Active After Transfer
#define SPI_SR_RDRF
(SPI_SR) Receive Data Register Full
#define SPI_CSR_NCPHA
(SPI_CSR[4]) Clock Phase
#define SPI_WPMR_WPEN
(SPI_WPMR) Write Protect Enable
#define SPI_TDR_PCS(value)
#define SPI_CSR_DLYBCT_Msk
(SPI_CSR[4]) Delay Between Consecutive Transfers
#define SPI_CSR_CSNAAT
(SPI_CSR[4]) Chip Select Not Active After Transfer (Ignored if CSAAT = 1)
int16_t spi_calc_baudrate_div(const uint32_t baudrate, uint32_t mck)
Calculate the baudrate divider.
Definition spi.c:362
int16_t spi_set_baudrate_div(Spi *p_spi, uint32_t ul_pcs_ch, uint8_t uc_baudrate_divider)
Set Serial Clock Baud Rate divider value (SCBR).
Definition spi.c:385
void spi_set_bits_per_transfer(Spi *p_spi, uint32_t ul_pcs_ch, uint32_t ul_bits)
Set number of bits per transfer.
Definition spi.c:345
void spi_set_transfer_delay(Spi *p_spi, uint32_t ul_pcs_ch, uint8_t uc_dlybs, uint8_t uc_dlybct)
Configure timing for SPI transfer.
Definition spi.c:405
void spi_set_clock_polarity(Spi *p_spi, uint32_t ul_pcs_ch, uint32_t ul_polarity)
Set clock default state.
Definition spi.c:290
void spi_configure_cs_behavior(Spi *p_spi, uint32_t ul_pcs_ch, uint32_t ul_cs_behavior)
Configure CS behavior for SPI transfer (spi_cs_behavior_t).
Definition spi.c:323
void spi_set_peripheral_chip_select_value(Spi *p_spi, uint32_t ul_value)
Set Peripheral Chip Select (PCS) value.
Definition spi.c:193
void spi_enable_clock(Spi *p_spi)
Enable SPI clock.
Definition spi.c:60
uint32_t spi_get_writeprotect_status(Spi *p_spi)
Indicate write protect status.
Definition spi.c:444
void spi_set_delay_between_chip_select(Spi *p_spi, uint32_t ul_delay)
Set delay between chip selects (in number of MCK clocks).
Definition spi.c:206
void spi_set_writeprotect(Spi *p_spi, uint32_t ul_enable)
Enable or disable write protection of SPI registers.
Definition spi.c:420
spi_status_t spi_read(Spi *p_spi, uint16_t *us_data, uint8_t *p_pcs)
Read the received data and it's peripheral chip select value.
Definition spi.c:224
#define SPI_WPMR_WPKEY_PASSWD
Definition spi.c:52
void spi_set_clock_phase(Spi *p_spi, uint32_t ul_pcs_ch, uint32_t ul_phase)
Set Data Capture Phase.
Definition spi.c:307
spi_status_t spi_write(Spi *p_spi, uint16_t us_data, uint8_t uc_pcs, uint8_t uc_last)
Write the transmitted data with specified peripheral chip select value.
Definition spi.c:257
void spi_disable_clock(Spi *p_spi)
Disable SPI clock.
Definition spi.c:123
#define ID_SPI
Serial Peripheral Interface (SPI).
Definition sam4sd32c.h:339
Serial Peripheral Interface (SPI) driver for SAM.
#define SPI_TIMEOUT
Time-out value (number of attempts).
Definition spi.h:51
@ SPI_CS_KEEP_LOW
CS does not rise until a new transfer is requested on different chip select.
Definition spi.h:68
@ SPI_CS_RISE_FORCED
CS is de-asserted systematically during a time DLYBCS.
Definition spi.h:72
@ SPI_CS_RISE_NO_TX
CS rises if there is no more data to transfer.
Definition spi.h:70
static uint32_t spi_get_peripheral_select_mode(Spi *p_spi)
Get Peripheral Select mode.
Definition spi.h:192
spi_status_t
Status codes used by the SPI driver.
Definition spi.h:55
@ SPI_OK
Definition spi.h:57
@ SPI_ERROR_TIMEOUT
Definition spi.h:58
Spi hardware registers.
__IO uint32_t SPI_MR
(Spi Offset: 0x04) Mode Register
__O uint32_t SPI_TDR
(Spi Offset: 0x0C) Transmit Data Register
__IO uint32_t SPI_WPMR
(Spi Offset: 0xE4) Write Protection Control Register
__IO uint32_t SPI_CSR[4]
(Spi Offset: 0x30) Chip Select Register
__I uint32_t SPI_WPSR
(Spi Offset: 0xE8) Write Protection Status Register
__I uint32_t SPI_SR
(Spi Offset: 0x10) Status Register
__I uint32_t SPI_RDR
(Spi Offset: 0x08) Receive Data Register