/* * \file * * \brief ATSHA204 file that implements the I2C layer for the device * * * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved. * * \asf_license_start * * \page License * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * * 4. This software may only be redistributed and used in connection with an * Atmel microcontroller product. * * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * \asf_license_stop * */ /* * Support and FAQ: visit Atmel Support */ #include "conf_twim.h" #include "conf_atsha204.h" #include "twi_master.h" #include "sha204_physical.h" // declarations that are common to all interface implementations #include "sha204_lib_return_codes.h" // declarations of function return codes #include "sha204_timer.h" // definitions for delay functions /** * \brief This enumeration lists all packet types sent to a SHA204 device. * * The following byte stream is sent to a SHA204 TWI device: * {I2C start} {I2C address} {word address} [{data}] {I2C stop}. * Data are only sent after a word address of value #SHA204_I2C_PACKET_FUNCTION_NORMAL. */ enum i2c_word_address { SHA204_I2C_PACKET_FUNCTION_RESET, //!< Reset device. SHA204_I2C_PACKET_FUNCTION_SLEEP, //!< Put device into Sleep mode. SHA204_I2C_PACKET_FUNCTION_IDLE, //!< Put device into Idle mode. SHA204_I2C_PACKET_FUNCTION_NORMAL //!< Write / evaluate data that follow this word address byte. }; //! I2C address can be changed by calling #sha204p_set_device_id. static uint8_t device_address = SHA204_I2C_DEFAULT_ADDRESS >> 1; /** \brief This function initializes peripherals (timer and communication). */ void sha204p_init(void) { // Initialize timer. sha204h_timer_init(); // Initialize interrupt vectors. irq_initialize_vectors(); // Enable interrupts. cpu_irq_enable(); } /** * \brief This I2C function sets the I2C address. * Communication functions will use this address. * * \param[in] id I2C address */ void sha204p_set_device_id(uint8_t id) { device_address = id >> 1; } /** * \brief This I2C function generates a Wake-up pulse and delays. * \return status of the operation */ uint8_t sha204p_wakeup(void) { twi_package_t twi_package; twi_options_t twi_options = {.speed = 133333}; // Set SDA low for 60 us. Speed is therefore: f = 1 / 0.00006 / 8 = 133,333. // Generating the Stop condition adds 20 us for this particular implementation / target, // but a longer wake pulse is okay. twi_master_disable(ATSHA204_TWI_PORT); int twi_master_setup_status = twi_master_setup(ATSHA204_TWI_PORT, &twi_options); if (twi_master_setup_status != STATUS_OK) return SHA204_COMM_FAIL; twi_package.chip = 0; twi_package.addr_length = 0; twi_package.length = 0; twi_package.buffer = NULL; // This call will return a nack error. (void) twi_master_write(ATSHA204_TWI_PORT, &twi_package); sha204h_delay_ms(SHA204_WAKEUP_DELAY); // Set I2C speed back to communication speed. twi_master_enable(ATSHA204_TWI_PORT); twi_options.speed = ATSHA204_TWI_SPEED; return (uint8_t) twi_master_setup(ATSHA204_TWI_PORT, &twi_options); } /** * \brief This function sends a I2C packet enclosed by a I2C start and stop to a SHA204 device. * * This function combines a I2C packet send sequence that is common to all packet types. * Only if word_address is \ref SHA204_I2C_PACKET_FUNCTION_NORMAL, count and buffer parameters are * expected to be non-zero. * \param[in] word_address packet function code listed in #i2c_word_address * \param[in] count number of bytes in data buffer * \param[in] buffer pointer to data buffer * \return status of the operation */ static uint8_t sha204p_send(uint8_t word_address, uint8_t count, uint8_t *buffer) { twi_package_t twi_package = { .chip = device_address, .addr_length = 1, .length = count, .buffer = (void *) buffer, .addr[0] = word_address }; return (twi_master_write(ATSHA204_TWI_PORT, &twi_package) ? SHA204_COMM_FAIL : SHA204_SUCCESS); } /** * \brief This I2C function sends a command to the device. * \param[in] count number of bytes to send * \param[in] command pointer to command buffer * \return status of the operation */ uint8_t sha204p_send_command(uint8_t count, uint8_t *command) { return sha204p_send(SHA204_I2C_PACKET_FUNCTION_NORMAL, count, command); } /** * \brief This I2C function puts the SHA204 device into idle state. * \return status of the operation */ uint8_t sha204p_idle(void) { return sha204p_send(SHA204_I2C_PACKET_FUNCTION_IDLE, 0, NULL); } /** * \brief This I2C function puts the SHA204 device into low-power state. * \return status of the operation */ uint8_t sha204p_sleep(void) { return sha204p_send(SHA204_I2C_PACKET_FUNCTION_SLEEP, 0, NULL); } /** * \brief This I2C function resets the I/O buffer of the SHA204 device. * \return status of the operation */ uint8_t sha204p_reset_io(void) { return sha204p_send(SHA204_I2C_PACKET_FUNCTION_RESET, 0, NULL); } /** * \brief This I2C function receives a response from the SHA204 device. * * \param[in] size size of receive buffer * \param[out] response pointer to receive buffer * \return status of the operation */ uint8_t sha204p_receive_response(uint8_t size, uint8_t *response) { // Read count. twi_package_t twi_package = { .chip = device_address, .addr_length = 0, .length = 1, .buffer = (void *) response }; status_code_t i2c_status = twi_master_read(ATSHA204_TWI_PORT, &twi_package); if (i2c_status != STATUS_OK) return (i2c_status == ERR_TIMEOUT ? SHA204_TIMEOUT : SHA204_RX_NO_RESPONSE); uint8_t count = response[SHA204_BUFFER_POS_COUNT]; if ((count < SHA204_RSP_SIZE_MIN) || (count > SHA204_RSP_SIZE_MAX)) return SHA204_INVALID_SIZE; // Read packet remainder. twi_package.length = (count > size) ? size : count; twi_package.length--; twi_package.buffer = response + 1; return (twi_master_read(ATSHA204_TWI_PORT, &twi_package) ? SHA204_COMM_FAIL : SHA204_SUCCESS); } /** * \brief This I2C function resynchronizes communication. * * Parameters are not used for I2C.\n * Re-synchronizing communication is done in a maximum of three steps * listed below. This function implements the first step. Since * steps 2 and 3 (sending a Wake-up token and reading the response) * are the same for I2C and SWI, they are * implemented in the communication layer (\ref sha204c_resync). * See the excerpt from the SHA204 data sheet below.