1 /*
2 * \file
3 *
4 * \brief ATSHA204 file that implements the I2C layer for the device
5 *
6 *
7 * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
8 *
9 * \asf_license_start
10 *
11 * \page License
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright notice,
20 * this list of conditions and the following disclaimer in the documentation
21 * and/or other materials provided with the distribution.
22 *
23 * 3. The name of Atmel may not be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * 4. This software may only be redistributed and used in connection with an
27 * Atmel microcontroller product.
28 *
29 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
30 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
32 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
33 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
40 *
41 * \asf_license_stop
42 *
43 */
44 /*
45 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
46 */
47
48 #include "conf_twim.h"
49 #include "conf_atsha204.h"
50 #include "twi_master.h"
51 #include "sha204_physical.h" // declarations that are common to all interface implementations
52 #include "sha204_lib_return_codes.h" // declarations of function return codes
53 #include "sha204_timer.h" // definitions for delay functions
54
55 /**
56 * \brief This enumeration lists all packet types sent to a SHA204 device.
57 *
58 * The following byte stream is sent to a SHA204 TWI device:
59 * {I2C start} {I2C address} {word address} [{data}] {I2C stop}.
60 * Data are only sent after a word address of value #SHA204_I2C_PACKET_FUNCTION_NORMAL.
61 */
62 enum i2c_word_address {
63 SHA204_I2C_PACKET_FUNCTION_RESET, //!< Reset device.
64 SHA204_I2C_PACKET_FUNCTION_SLEEP, //!< Put device into Sleep mode.
65 SHA204_I2C_PACKET_FUNCTION_IDLE, //!< Put device into Idle mode.
66 SHA204_I2C_PACKET_FUNCTION_NORMAL //!< Write / evaluate data that follow this word address byte.
67 };
68
69
70 //! I2C address can be changed by calling #sha204p_set_device_id.
71 static uint8_t device_address = SHA204_I2C_DEFAULT_ADDRESS >> 1;
72
73
74 /** \brief This function initializes peripherals (timer and communication).
75 */
sha204p_init(void)76 void sha204p_init(void)
77 {
78 // Initialize timer.
79 sha204h_timer_init();
80
81 // Initialize interrupt vectors.
82 irq_initialize_vectors();
83
84 // Enable interrupts.
85 cpu_irq_enable();
86 }
87
88
89 /**
90 * \brief This I2C function sets the I2C address.
91 * Communication functions will use this address.
92 *
93 * \param[in] id I2C address
94 */
sha204p_set_device_id(uint8_t id)95 void sha204p_set_device_id(uint8_t id)
96 {
97 device_address = id >> 1;
98 }
99
100
101 /**
102 * \brief This I2C function generates a Wake-up pulse and delays.
103 * \return status of the operation
104 */
sha204p_wakeup(void)105 uint8_t sha204p_wakeup(void)
106 {
107 twi_package_t twi_package;
108 twi_options_t twi_options = {.speed = 133333};
109
110 // Set SDA low for 60 us. Speed is therefore: f = 1 / 0.00006 / 8 = 133,333.
111 // Generating the Stop condition adds 20 us for this particular implementation / target,
112 // but a longer wake pulse is okay.
113 twi_master_disable(ATSHA204_TWI_PORT);
114 int twi_master_setup_status = twi_master_setup(ATSHA204_TWI_PORT, &twi_options);
115 if (twi_master_setup_status != STATUS_OK)
116 return SHA204_COMM_FAIL;
117
118 twi_package.chip = 0;
119 twi_package.addr_length = 0;
120 twi_package.length = 0;
121 twi_package.buffer = NULL;
122
123 // This call will return a nack error.
124 (void) twi_master_write(ATSHA204_TWI_PORT, &twi_package);
125
126 sha204h_delay_ms(SHA204_WAKEUP_DELAY);
127
128 // Set I2C speed back to communication speed.
129 twi_master_enable(ATSHA204_TWI_PORT);
130 twi_options.speed = ATSHA204_TWI_SPEED;
131 return (uint8_t) twi_master_setup(ATSHA204_TWI_PORT, &twi_options);
132 }
133
134
135 /**
136 * \brief This function sends a I2C packet enclosed by a I2C start and stop to a SHA204 device.
137 *
138 * This function combines a I2C packet send sequence that is common to all packet types.
139 * Only if word_address is \ref SHA204_I2C_PACKET_FUNCTION_NORMAL, count and buffer parameters are
140 * expected to be non-zero.
141 * \param[in] word_address packet function code listed in #i2c_word_address
142 * \param[in] count number of bytes in data buffer
143 * \param[in] buffer pointer to data buffer
144 * \return status of the operation
145 */
sha204p_send(uint8_t word_address,uint8_t count,uint8_t * buffer)146 static uint8_t sha204p_send(uint8_t word_address, uint8_t count, uint8_t *buffer)
147 {
148 twi_package_t twi_package = {
149 .chip = device_address,
150 .addr_length = 1,
151 .length = count,
152 .buffer = (void *) buffer,
153 .addr[0] = word_address
154 };
155 return (twi_master_write(ATSHA204_TWI_PORT, &twi_package) ? SHA204_COMM_FAIL : SHA204_SUCCESS);
156 }
157
158
159 /**
160 * \brief This I2C function sends a command to the device.
161 * \param[in] count number of bytes to send
162 * \param[in] command pointer to command buffer
163 * \return status of the operation
164 */
sha204p_send_command(uint8_t count,uint8_t * command)165 uint8_t sha204p_send_command(uint8_t count, uint8_t *command)
166 {
167 return sha204p_send(SHA204_I2C_PACKET_FUNCTION_NORMAL, count, command);
168 }
169
170
171 /**
172 * \brief This I2C function puts the SHA204 device into idle state.
173 * \return status of the operation
174 */
sha204p_idle(void)175 uint8_t sha204p_idle(void)
176 {
177 return sha204p_send(SHA204_I2C_PACKET_FUNCTION_IDLE, 0, NULL);
178 }
179
180
181 /**
182 * \brief This I2C function puts the SHA204 device into low-power state.
183 * \return status of the operation
184 */
sha204p_sleep(void)185 uint8_t sha204p_sleep(void)
186 {
187 return sha204p_send(SHA204_I2C_PACKET_FUNCTION_SLEEP, 0, NULL);
188 }
189
190
191 /**
192 * \brief This I2C function resets the I/O buffer of the SHA204 device.
193 * \return status of the operation
194 */
sha204p_reset_io(void)195 uint8_t sha204p_reset_io(void)
196 {
197 return sha204p_send(SHA204_I2C_PACKET_FUNCTION_RESET, 0, NULL);
198 }
199
200
201 /**
202 * \brief This I2C function receives a response from the SHA204 device.
203 *
204 * \param[in] size size of receive buffer
205 * \param[out] response pointer to receive buffer
206 * \return status of the operation
207 */
sha204p_receive_response(uint8_t size,uint8_t * response)208 uint8_t sha204p_receive_response(uint8_t size, uint8_t *response)
209 {
210 // Read count.
211 twi_package_t twi_package = {
212 .chip = device_address,
213 .addr_length = 0,
214 .length = 1,
215 .buffer = (void *) response
216 };
217 status_code_t i2c_status = twi_master_read(ATSHA204_TWI_PORT, &twi_package);
218 if (i2c_status != STATUS_OK)
219 return (i2c_status == ERR_TIMEOUT ? SHA204_TIMEOUT : SHA204_RX_NO_RESPONSE);
220
221 uint8_t count = response[SHA204_BUFFER_POS_COUNT];
222 if ((count < SHA204_RSP_SIZE_MIN) || (count > SHA204_RSP_SIZE_MAX))
223 return SHA204_INVALID_SIZE;
224
225 // Read packet remainder.
226 twi_package.length = (count > size) ? size : count;
227 twi_package.length--;
228 twi_package.buffer = response + 1;
229 return (twi_master_read(ATSHA204_TWI_PORT, &twi_package) ? SHA204_COMM_FAIL : SHA204_SUCCESS);
230 }
231
232
233 /**
234 * \brief This I2C function resynchronizes communication.
235 *
236 * Parameters are not used for I2C.\n
237 * Re-synchronizing communication is done in a maximum of three steps
238 * listed below. This function implements the first step. Since
239 * steps 2 and 3 (sending a Wake-up token and reading the response)
240 * are the same for I2C and SWI, they are
241 * implemented in the communication layer (\ref sha204c_resync).
242 * See the excerpt from the SHA204 data sheet below.
243 <ol>
244 <li>
245 To ensure an IO channel reset, the system should send
246 the standard I2C software reset sequence, as follows:
247 <ul>
248 <li>a Start condition</li>
249 <li>nine cycles of SCL, with SDA held high</li>
250 <li>another Start condition</li>
251 <li>a Stop condition</li>
252 </ul>
253 It should then be possible to send a read sequence and
254 if synchronization has completed properly the ATSHA204 will
255 acknowledge the device address. The chip may return data or
256 may leave the bus floating (which the system will interpret
257 as a data value of 0xFF) during the data periods.\n
258 If the chip does acknowledge the device address, the system
259 should reset the internal address counter to force the
260 ATSHA204 to ignore any partial input command that may have
261 been sent. This can be accomplished by sending a write
262 sequence to word address 0x00 (Reset), followed by a
263 Stop condition.
264 </li>
265 <li>
266 If the chip does NOT respond to the device address with an ACK,
267 then it may be asleep. In this case, the system should send a
268 complete Wake token and wait t_whi after the rising edge. The
269 system may then send another read sequence and if synchronization
270 has completed the chip will acknowledge the device address.
271 </li>
272 <li>
273 If the chip still does not respond to the device address with
274 an acknowledge, then it may be busy executing a command. The
275 system should wait the longest TEXEC and then send the
276 read sequence, which will be acknowledged by the chip.
277 </li>
278 </ol>
279 * \param[in] size size of response buffer
280 * \param[out] response pointer to response buffer
281 * \return status of the operation
282 */
sha204p_resync(uint8_t size,uint8_t * response)283 uint8_t sha204p_resync(uint8_t size, uint8_t *response)
284 {
285 // Generate Start, nine clocks, Stop.
286 // (Adding a Repeat Start before the Stop would additionally
287 // prevent erroneously writing a byte, but a Stop right after a
288 // Start is not "legal" for I2C and the SHA204 will not write
289 // anything without a successful CRC check.)
290 twi_package_t twi_package = {
291 .chip = (uint8_t) 0xFF,
292 .addr_length = 1,
293 .length = 0,
294 .buffer = (void *) response,
295 .addr[0] = 0
296 };
297 (void) twi_master_read(ATSHA204_TWI_PORT, &twi_package);
298
299 return sha204p_reset_io();
300 }
301