1 /**
2  * \file
3  *
4  * \brief SAM USART in SPI mode driver functions.
5  *
6  * Copyright (c) 2011-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 
47 #include "usart_spi.h"
48 #include "sysclk.h"
49 #if SAMG55
50 #include "flexcom.h"
51 #include "conf_board.h"
52 #endif
53 
54 /// @cond 0
55 /**INDENT-OFF**/
56 #ifdef __cplusplus
57 extern "C" {
58 #endif
59 /**INDENT-ON**/
60 /// @endcond
61 
62 /*! \brief Enable the USART system clock in SPI master mode.
63  *
64  * \param p_usart Pointer to Base address of the USART instance.
65  *
66  */
usart_spi_init(Usart * p_usart)67 void usart_spi_init(Usart *p_usart)
68 {
69 #if (!SAMG55)
70 
71 	uint8_t uc_id;
72 
73 #ifdef USART0
74 	if (p_usart == USART0) {
75 		uc_id = ID_USART0;
76 	}
77 #endif
78 
79 #ifdef USART1
80 	else if(p_usart == USART1) {
81 		uc_id = ID_USART1;
82 	}
83 #endif
84 
85 #ifdef USART2
86 	else if(p_usart == USART2) {
87 		uc_id = ID_USART2;
88 	}
89 #endif
90 
91 #ifdef USART3
92 	else if(p_usart == USART3) {
93 		uc_id = ID_USART3;
94 	}
95 #endif
96 
97 #endif
98 
99 #if SAM4L
100 	sysclk_enable_peripheral_clock(p_usart);
101 #elif SAMG55
102 	flexcom_enable(BOARD_FLEXCOM_USART);
103 	flexcom_set_opmode(BOARD_FLEXCOM_USART, FLEXCOM_USART);
104 #else
105 	sysclk_enable_peripheral_clock(uc_id);
106 #endif
107 }
108 
109 /**
110  * \brief Set up a USART in SPI master mode device.
111  *
112  * The returned device descriptor structure must be passed to the driver
113  * whenever that device should be used as current slave device.
114  *
115  * \param p_usart   Base address of the USART instance.
116  * \param device    Pointer to usart device struct that should be initialized.
117  * \param flags     USART configuration flags. Common flags for all
118  *                  implementations are the usart modes, which should be SPI_MODE_0,
119  *                  SPI_MODE_1, SPI_MODE_2, SPI_MODE_3.
120  * \param baud_rate Baud rate for communication with slave device in Hz.
121  * \param sel_id    Board specific select id.
122  */
usart_spi_setup_device(Usart * p_usart,struct usart_spi_device * device,spi_flags_t flags,unsigned long baud_rate,board_spi_select_id_t sel_id)123 void usart_spi_setup_device(Usart *p_usart, struct usart_spi_device *device,
124      spi_flags_t flags, unsigned long baud_rate,
125      board_spi_select_id_t sel_id)
126 {
127 	usart_spi_opt_t opt;
128 
129 	/* avoid Cppcheck Warning */
130 	UNUSED(device);
131 	UNUSED(sel_id);
132 
133 	/* Basic usart SPI configuration. */
134 	opt.baudrate = baud_rate;
135 	opt.char_length = US_MR_CHRL_8_BIT;
136 	opt.spi_mode = flags;
137 	opt.channel_mode = US_MR_CHMODE_NORMAL;
138 
139 	/* Initialize the USART module as SPI master. */
140 #if (SAM4L)
141 	usart_init_spi_master(p_usart, &opt, sysclk_get_pba_hz());
142 #else
143 	usart_init_spi_master(p_usart, &opt, sysclk_get_peripheral_hz());
144 #endif
145 
146 	usart_enable_rx(p_usart);
147 	usart_enable_tx(p_usart);
148 }
149 
150 /*! \brief Write one byte to an SPI device using USART in SPI mode.
151  *
152  * \param p_usart Base address of the USART instance.
153  * \param data    The data to be sent out.
154  *
155  */
usart_spi_write_single(Usart * p_usart,uint8_t data)156 void usart_spi_write_single(Usart *p_usart, uint8_t data)
157 {
158 	usart_putchar(p_usart, data);
159 }
160 
161 /**
162  * \brief Send a sequence of bytes to an SPI device using USART in SPI mode.
163  *
164  * Received bytes on the USART in SPI mode are discarded.
165  *
166  * \param p_usart Base address of the USART instance.
167  * \param data    Data buffer to write.
168  * \param len     Length of data.
169  *
170  * \return 0 if the USART in SPI master mode sends packet successfully.
171  *
172  * \pre USART device must be selected with usart_spi_select_device() first.
173  */
usart_spi_write_packet(Usart * p_usart,const uint8_t * data,size_t len)174 uint32_t usart_spi_write_packet(Usart *p_usart, const uint8_t *data, size_t len)
175 {
176 	uint32_t dummy_data;
177 	size_t i=0;
178 	while(len) {
179 		usart_putchar(p_usart, *(data+i));
180 		usart_getchar(p_usart, &dummy_data);
181 		len--;
182 		i++;
183 	}
184 	return 0;
185 }
186 
187 /*! \brief Receive one byte from an SPI device using USART in SPI mode.
188  *
189  * \param p_usart Base address of the USART instance.
190  * \param data    Pointer to the data byte where to store the received data.
191  *
192  * \pre USART device must be selected with usart_spi_select_device() first.
193  */
usart_spi_read_single(Usart * p_usart,uint8_t * data)194 void usart_spi_read_single(Usart *p_usart, uint8_t *data)
195 {
196 	uint32_t temp_data = 0;
197 	/* Dummy write one data to slave in order to read data. */
198 	usart_putchar(p_usart, CONFIG_USART_SPI_DUMMY);
199 
200 	usart_getchar(p_usart, &temp_data);
201 	*data = (uint8_t)temp_data;
202 }
203 
204 /**
205  * \brief Receive a sequence of bytes from a USART in SPI mode device.
206  *
207  * All bytes sent out on usart bus are sent as value 0.
208  *
209  * \param p_usart Base address of the usart instance.
210  * \param data    Data buffer to put read data.
211  * \param len     Length of data.
212  *
213  * \return 0 if the USART in SPI master mode reads packet successfully.
214  *
215  * \pre USART device must be selected with usart_spi_select_device() first.
216  */
usart_spi_read_packet(Usart * p_usart,uint8_t * data,size_t len)217 uint32_t usart_spi_read_packet(Usart *p_usart, uint8_t *data, size_t len)
218 {
219 	uint32_t val;
220 	uint32_t i = 0;
221 
222 	while(len) {
223 		/* Dummy write one data to slave in order to read data. */
224 		usart_putchar(p_usart, CONFIG_USART_SPI_DUMMY);
225 		usart_getchar(p_usart, &val);
226 
227 		data[i] = (uint8_t)(val & 0xFF);
228 		i++;
229 		len--;
230 	}
231 
232 	return 0;
233 }
234 
235 /**
236  * \brief Select the given device on the SPI bus.
237  *
238  * \param p_usart  Base address of the USART instance.
239  * \param device   SPI device.
240  *
241  */
usart_spi_select_device(Usart * p_usart,struct usart_spi_device * device)242 void usart_spi_select_device(Usart *p_usart, struct usart_spi_device *device)
243 {
244 	/* avoid Cppcheck Warning */
245 	UNUSED(device);
246 
247 	usart_spi_force_chip_select(p_usart);
248 }
249 
250 /**
251  * \brief De-select the given device on the SPI bus.
252  *
253  * \param p_usart Base address of the USART instance.
254  * \param device  SPI device.
255  */
usart_spi_deselect_device(Usart * p_usart,struct usart_spi_device * device)256 void usart_spi_deselect_device(Usart *p_usart, struct usart_spi_device *device)
257 {
258 	/* avoid Cppcheck Warning */
259 	UNUSED(device);
260 
261 	usart_spi_release_chip_select(p_usart);
262 }
263 
264 /*! \brief Check whether there are data in Transmit Holding Register or
265  *         Transmit Shift Register in SPI master mode.
266  *
267  * \param p_usart Base address of the USART instance.
268  *
269  * \retval 1      The two registers are empty.
270  * \retval 0      One of the two registers contains data.
271  */
usart_spi_is_tx_empty(Usart * p_usart)272 uint32_t usart_spi_is_tx_empty(Usart *p_usart)
273 {
274 	return usart_is_tx_empty(p_usart);
275 }
276 
277 /*! \brief Check whether the USART in SPI master mode contains a received character.
278  *
279  * \param p_usart Base address of the USART instance.
280  *
281  * \retval 1      Some data have been received.
282  * \retval 0      No data has been received.
283  */
usart_spi_is_rx_ready(Usart * p_usart)284 uint32_t usart_spi_is_rx_ready(Usart *p_usart)
285 {
286 	return usart_is_rx_ready(p_usart);
287 }
288 
289 /*! \brief Check if the USART Transmit Holding Register is empty or not in SPI mode.
290  *
291  * \param p_usart Base address of the USART instance.
292  *
293  * \retval 1      There is no data in the Transmit Holding Register.
294  * \retval 0      There are data in the Transmit Holding Register.
295  */
usart_spi_is_tx_ready(Usart * p_usart)296 uint32_t usart_spi_is_tx_ready(Usart *p_usart)
297 {
298 	return usart_is_tx_ready(p_usart);
299 }
300 
301 /*! \brief Check if both receive buffers are full.
302  *
303  * \param p_usart Base address of the USART instance.
304  *
305  * \retval 1      Receive buffers are full.
306  * \retval 0      Receive buffers are not full.
307  */
usart_spi_is_rx_full(Usart * p_usart)308 uint32_t usart_spi_is_rx_full(Usart *p_usart)
309 {
310 #if (!SAMV71 && !SAMV70 && !SAME70 && !SAMS70)
311 	return usart_is_rx_buf_full(p_usart);
312 #endif
313 }
314 
315 /*! \brief Enable the USART for the specified USART in SPI mode.
316  *
317  * \param p_usart Base address of the USART instance.
318  */
usart_spi_enable(Usart * p_usart)319 void usart_spi_enable(Usart *p_usart)
320 {
321 	usart_enable_tx(p_usart);
322 	usart_enable_rx(p_usart);
323 }
324 
325 /*! \brief Disable the USART for the specified USART in SPI mode.
326  *
327  * Ensure that nothing is transferred while setting up buffers.
328  *
329  * \param p_usart Base address of the USART instance.
330  *
331  */
usart_spi_disable(Usart * p_usart)332 void usart_spi_disable(Usart *p_usart)
333 {
334 	usart_disable_tx(p_usart);
335 	usart_disable_rx(p_usart);
336 }
337 
338 /// @cond 0
339 /**INDENT-OFF**/
340 #ifdef __cplusplus
341 }
342 #endif
343 /**INDENT-ON**/
344 /// @endcond
345