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