]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libchip_samv7/source/twi.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libchip_samv7 / source / twi.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2011, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \addtogroup twi_module Working with TWI\r
31  *  \ingroup peripherals_module\r
32  * The TWI driver provides the interface to configure and use the TWI\r
33  * peripheral.\r
34  *\r
35  * \section Usage\r
36  * <ul>\r
37  * <li> Configures a TWI peripheral to operate in master mode, at the given\r
38  * frequency (in Hz) using TWI_Configure(). </li>\r
39  * <li> Sends a STOP condition on the TWI using TWI_Stop().</li>\r
40  * <li> Starts a read operation on the TWI bus with the specified slave using\r
41  * TWI_StartRead(). Data must then be read using TWI_ReadByte() whenever\r
42  * a byte is available (poll using TWI_ByteReceived()).</li>\r
43  * <li> Starts a write operation on the TWI to access the selected slave using\r
44  * TWI_StartWrite(). A byte of data must be provided to start the write;\r
45  * other bytes are written next.</li>\r
46  * <li> Sends a byte of data to one of the TWI slaves on the bus using TWI_WriteByte().\r
47  * This function must be called once before TWI_StartWrite() with the first byte of data\r
48  * to send, then it shall be called repeatedly after that to send the remaining bytes.</li>\r
49  * <li> Check if a byte has been received and can be read on the given TWI\r
50  * peripheral using TWI_ByteReceived().<\r
51  * Check if a byte has been sent using TWI_ByteSent().</li>\r
52  * <li> Check if the current transmission is complete (the STOP has been sent)\r
53  * using TWI_TransferComplete().</li>\r
54  * <li> Enables & disable the selected interrupts sources on a TWI peripheral\r
55  * using TWI_EnableIt() and TWI_DisableIt().</li>\r
56  * <li> Get current status register of the given TWI peripheral using\r
57  * TWI_GetStatus(). Get current status register of the given TWI peripheral, but\r
58  * masking interrupt sources which are not currently enabled using\r
59  * TWI_GetMaskedStatus().</li>\r
60  * </ul>\r
61  * For more accurate information, please look at the TWI section of the\r
62  * Datasheet.\r
63  *\r
64  * Related files :\n\r
65  * \ref twi.c\n\r
66  * \ref twi.h.\n\r
67 */\r
68 /*@{*/\r
69 /*@}*/\r
70 \r
71 /**\r
72  * \file\r
73  *\r
74  * Implementation of Two Wire Interface (TWI).\r
75  *\r
76  */\r
77 \r
78 /*----------------------------------------------------------------------------\r
79  *        Headers\r
80  *----------------------------------------------------------------------------*/\r
81 \r
82 #include "chip.h"\r
83 \r
84 #include <assert.h>\r
85 \r
86 /*----------------------------------------------------------------------------\r
87  *        Exported functions\r
88  *----------------------------------------------------------------------------*/\r
89 \r
90 /**\r
91  * \brief Configures a TWI peripheral to operate in master mode, at the given\r
92  * frequency (in Hz). The duty cycle of the TWI clock is set to 50%.\r
93  * \param pTwi  Pointer to an Twihs instance.\r
94  * \param twck  Desired TWI clock frequency.\r
95  * \param mck  Master clock frequency.\r
96  */\r
97 void TWI_ConfigureMaster( Twihs *pTwi, uint32_t dwTwCk, uint32_t dwMCk )\r
98 {\r
99     uint32_t dwCkDiv = 0 ;\r
100     uint32_t dwClDiv ;\r
101     uint32_t dwOk = 0 ;\r
102 \r
103     TRACE_DEBUG( "TWI_ConfigureMaster()\n\r" ) ;\r
104     assert( pTwi ) ;\r
105 \r
106     /* SVEN: TWI Slave Mode Enabled */\r
107     pTwi->TWIHS_CR = TWIHS_CR_SVEN ;\r
108     /* Reset the TWI */\r
109     pTwi->TWIHS_CR = TWIHS_CR_SWRST ;\r
110     pTwi->TWIHS_RHR ;\r
111 \r
112     /* TWI Slave Mode Disabled, TWI Master Mode Disabled. */\r
113     pTwi->TWIHS_CR = TWIHS_CR_SVDIS ;\r
114     pTwi->TWIHS_CR = TWIHS_CR_MSDIS ;\r
115 \r
116     /* Set master mode */\r
117     pTwi->TWIHS_CR = TWIHS_CR_MSEN ;\r
118 \r
119     /* Configure clock */\r
120     while ( !dwOk )\r
121     {\r
122         dwClDiv = ((dwMCk / (2 * dwTwCk)) - 4) / (1<<dwCkDiv) ;\r
123 \r
124         if ( dwClDiv <= 255 )\r
125         {\r
126             dwOk = 1 ;\r
127         }\r
128         else\r
129         {\r
130             dwCkDiv++ ;\r
131         }\r
132     }\r
133 \r
134     assert( dwCkDiv < 8 ) ;\r
135     TRACE_DEBUG( "Using CKDIV = %u and CLDIV/CHDIV = %u\n\r", dwCkDiv, dwClDiv ) ;\r
136 \r
137     pTwi->TWIHS_CWGR = 0 ;\r
138     pTwi->TWIHS_CWGR = (dwCkDiv << 16) | (dwClDiv << 8) | dwClDiv ;\r
139 }\r
140 \r
141 /**\r
142  * \brief Configures a TWI peripheral to operate in slave mode.\r
143  * \param pTwi  Pointer to an Twihs instance.\r
144  * \param slaveAddress Slave address.\r
145  */\r
146 void TWI_ConfigureSlave(Twihs *pTwi, uint8_t slaveAddress)\r
147 {\r
148     uint32_t i;\r
149 \r
150     /* TWI software reset */\r
151     pTwi->TWIHS_CR = TWIHS_CR_SWRST;\r
152     pTwi->TWIHS_RHR;\r
153 \r
154     /* Wait at least 10 ms */\r
155     for (i=0; i < 1000000; i++);\r
156 \r
157     /* TWI Slave Mode Disabled, TWI Master Mode Disabled*/\r
158     pTwi->TWIHS_CR = TWIHS_CR_SVDIS | TWIHS_CR_MSDIS;\r
159 \r
160     /* Configure slave address. */\r
161     pTwi->TWIHS_SMR = 0;\r
162     pTwi->TWIHS_SMR = TWIHS_SMR_SADR(slaveAddress);\r
163 \r
164     /* SVEN: TWI Slave Mode Enabled */\r
165     pTwi->TWIHS_CR = TWIHS_CR_SVEN;\r
166 \r
167     /* Wait at least 10 ms */\r
168     for (i=0; i < 1000000; i++);\r
169     assert( (pTwi->TWIHS_CR & TWIHS_CR_SVDIS)!= TWIHS_CR_SVDIS ) ;\r
170 }\r
171 \r
172 /**\r
173  * \brief Sends a STOP condition on the TWI.\r
174  * \param pTwi  Pointer to an Twihs instance.\r
175  */\r
176 void TWI_Stop( Twihs *pTwi )\r
177 {\r
178     assert( pTwi != NULL ) ;\r
179 \r
180     pTwi->TWIHS_CR = TWIHS_CR_STOP;\r
181 }\r
182 \r
183 /**\r
184  * \brief Starts a read operation on the TWI bus with the specified slave, it returns\r
185  * immediately. Data must then be read using TWI_ReadByte() whenever a byte is\r
186  * available (poll using TWI_ByteReceived()).\r
187  * \param pTwi  Pointer to an Twihs instance.\r
188  * \param address  Slave address on the bus.\r
189  * \param iaddress  Optional internal address bytes.\r
190  * \param isize  Number of internal address bytes.\r
191  */\r
192 void TWI_StartRead(\r
193     Twihs *pTwi,\r
194     uint8_t address,\r
195     uint32_t iaddress,\r
196     uint8_t isize)\r
197 {\r
198     assert( pTwi != NULL ) ;\r
199     assert( (address & 0x80) == 0 ) ;\r
200     assert( (iaddress & 0xFF000000) == 0 ) ;\r
201     assert( isize < 4 ) ;\r
202 \r
203     /* Set slave address and number of internal address bytes. */\r
204     pTwi->TWIHS_MMR = 0;\r
205     pTwi->TWIHS_MMR = (isize << 8) | TWIHS_MMR_MREAD | (address << 16);\r
206 \r
207     /* Set internal address bytes */\r
208     pTwi->TWIHS_IADR = 0;\r
209     pTwi->TWIHS_IADR = iaddress;\r
210 \r
211     /* Send START condition */\r
212     pTwi->TWIHS_CR = TWIHS_CR_START;\r
213 }\r
214 \r
215 /**\r
216  * \brief Reads a byte from the TWI bus. The read operation must have been started\r
217  * using TWI_StartRead() and a byte must be available (check with TWI_ByteReceived()).\r
218  * \param pTwi  Pointer to an Twihs instance.\r
219  * \return byte read.\r
220  */\r
221 uint8_t TWI_ReadByte(Twihs *pTwi)\r
222 {\r
223     assert( pTwi != NULL ) ;\r
224 \r
225     return pTwi->TWIHS_RHR;\r
226 }\r
227 \r
228 /**\r
229  * \brief Sends a byte of data to one of the TWI slaves on the bus.\r
230  * \note This function must be called once before TWI_StartWrite() with\r
231  * the first byte of data  to send, then it shall be called repeatedly\r
232  * after that to send the remaining bytes.\r
233  * \param pTwi  Pointer to an Twihs instance.\r
234  * \param byte  Byte to send.\r
235  */\r
236 void TWI_WriteByte(Twihs *pTwi, uint8_t byte)\r
237 {\r
238     assert( pTwi != NULL ) ;\r
239 \r
240     pTwi->TWIHS_THR = byte;\r
241 }\r
242 \r
243 /**\r
244  * \brief Starts a write operation on the TWI to access the selected slave, then\r
245  *  returns immediately. A byte of data must be provided to start the write;\r
246  * other bytes are written next.\r
247  * after that to send the remaining bytes.\r
248  * \param pTwi  Pointer to an Twihs instance.\r
249  * \param address  Address of slave to acccess on the bus.\r
250  * \param iaddress  Optional slave internal address.\r
251  * \param isize  Number of internal address bytes.\r
252  * \param byte  First byte to send.\r
253  */\r
254 void TWI_StartWrite(\r
255     Twihs *pTwi,\r
256     uint8_t address,\r
257     uint32_t iaddress,\r
258     uint8_t isize,\r
259     uint8_t byte)\r
260 {\r
261     assert( pTwi != NULL ) ;\r
262     assert( (address & 0x80) == 0 ) ;\r
263     assert( (iaddress & 0xFF000000) == 0 ) ;\r
264     assert( isize < 4 ) ;\r
265 \r
266     /* Set slave address and number of internal address bytes. */\r
267     pTwi->TWIHS_MMR = 0;\r
268     pTwi->TWIHS_MMR = (isize << 8) | (address << 16);\r
269 \r
270     /* Set internal address bytes. */\r
271     pTwi->TWIHS_IADR = 0;\r
272     pTwi->TWIHS_IADR = iaddress;\r
273 \r
274     /* Write first byte to send.*/\r
275     TWI_WriteByte(pTwi, byte);\r
276 }\r
277 \r
278 /**\r
279  * \brief Check if a byte have been receiced from TWI.\r
280  * \param pTwi  Pointer to an Twihs instance.\r
281  * \return 1 if a byte has been received and can be read on the given TWI\r
282  * peripheral; otherwise, returns 0. This function resets the status register.\r
283  */\r
284 uint8_t TWI_ByteReceived(Twihs *pTwi)\r
285 {\r
286     return ((pTwi->TWIHS_SR & TWIHS_SR_RXRDY) == TWIHS_SR_RXRDY);\r
287 }\r
288 \r
289 /**\r
290  * \brief Check if a byte have been sent to TWI.\r
291  * \param pTwi  Pointer to an Twihs instance.\r
292  * \return 1 if a byte has been sent  so another one can be stored for\r
293  * transmission; otherwise returns 0. This function clears the status register.\r
294  */\r
295 uint8_t TWI_ByteSent(Twihs *pTwi)\r
296 {\r
297     return ((pTwi->TWIHS_SR & TWIHS_SR_TXRDY) == TWIHS_SR_TXRDY);\r
298 }\r
299 \r
300 /**\r
301  * \brief Check if current transmission is complet.\r
302  * \param pTwi  Pointer to an Twihs instance.\r
303  * \return  1 if the current transmission is complete (the STOP has been sent);\r
304  * otherwise returns 0.\r
305  */\r
306 uint8_t TWI_TransferComplete(Twihs *pTwi)\r
307 {\r
308     return ((pTwi->TWIHS_SR & TWIHS_SR_TXCOMP) == TWIHS_SR_TXCOMP);\r
309 }\r
310 \r
311 /**\r
312  * \brief Enables the selected interrupts sources on a TWI peripheral.\r
313  * \param pTwi  Pointer to an Twihs instance.\r
314  * \param sources  Bitwise OR of selected interrupt sources.\r
315  */\r
316 void TWI_EnableIt(Twihs *pTwi, uint32_t sources)\r
317 {\r
318     assert( pTwi != NULL ) ;\r
319     assert( (sources & 0xFFFFF088) == 0 ) ;\r
320 \r
321     pTwi->TWIHS_IER = sources;\r
322 }\r
323 \r
324 /**\r
325  * \brief Disables the selected interrupts sources on a TWI peripheral.\r
326  * \param pTwi  Pointer to an Twihs instance.\r
327  * \param sources  Bitwise OR of selected interrupt sources.\r
328  */\r
329 void TWI_DisableIt(Twihs *pTwi, uint32_t sources)\r
330 {\r
331     assert( pTwi != NULL ) ;\r
332     assert( (sources & 0xFFFFF088) == 0 ) ;\r
333 \r
334     pTwi->TWIHS_IDR = sources;\r
335 }\r
336 \r
337 /**\r
338  * \brief Get the current status register of the given TWI peripheral.\r
339  * \note This resets the internal value of the status register, so further\r
340  * read may yield different values.\r
341  * \param pTwi  Pointer to an Twihs instance.\r
342  * \return  TWI status register.\r
343  */\r
344 uint32_t TWI_GetStatus(Twihs *pTwi)\r
345 {\r
346     assert( pTwi != NULL ) ;\r
347 \r
348     return pTwi->TWIHS_SR;\r
349 }\r
350 \r
351 /**\r
352  * \brief Returns the current status register of the given TWI peripheral, but\r
353  * masking interrupt sources which are not currently enabled.\r
354  * \note This resets the internal value of the status register, so further\r
355  * read may yield different values.\r
356  * \param pTwi  Pointer to an Twihs instance.\r
357  */\r
358 uint32_t TWI_GetMaskedStatus(Twihs *pTwi)\r
359 {\r
360     uint32_t status;\r
361 \r
362     assert( pTwi != NULL ) ;\r
363 \r
364     status = pTwi->TWIHS_SR;\r
365     status &= pTwi->TWIHS_IMR;\r
366 \r
367     return status;\r
368 }\r
369 \r
370 /**\r
371  * \brief  Sends a STOP condition. STOP Condition is sent just after completing\r
372  *  the current byte transmission in master read mode.\r
373  * \param pTwi  Pointer to an Twihs instance.\r
374  */\r
375 void TWI_SendSTOPCondition(Twihs *pTwi)\r
376 {\r
377     assert( pTwi != NULL ) ;\r
378 \r
379     pTwi->TWIHS_CR |= TWIHS_CR_STOP;\r
380 }\r
381 \r