You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					107 lines
				
				2.5 KiB
			
		
		
			
		
	
	
					107 lines
				
				2.5 KiB
			|   
											8 years ago
										 | /*
 | ||
|  | Copyright 2016 Luiz Ribeiro <luizribeiro@gmail.com> | ||
|  | 
 | ||
|  | This program is free software: you can redistribute it and/or modify | ||
|  | it under the terms of the GNU General Public License as published by | ||
|  | the Free Software Foundation, either version 2 of the License, or | ||
|  | (at your option) any later version. | ||
|  | 
 | ||
|  | This program is distributed in the hope that it will be useful, | ||
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||
|  | GNU General Public License for more details. | ||
|  | 
 | ||
|  | You should have received a copy of the GNU General Public License | ||
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||
|  | */ | ||
|  | 
 | ||
|  | // Please do not modify this file
 | ||
|  | 
 | ||
|  | #include <avr/io.h>
 | ||
|  | #include <util/twi.h>
 | ||
|  | 
 | ||
|  | #include "i2c.h"
 | ||
|  | 
 | ||
|  | void i2c_set_bitrate(uint16_t bitrate_khz) { | ||
|  |     uint8_t bitrate_div = ((F_CPU / 1000l) / bitrate_khz); | ||
|  |     if (bitrate_div >= 16) { | ||
|  |         bitrate_div = (bitrate_div - 16) / 2; | ||
|  |     } | ||
|  |     TWBR = bitrate_div; | ||
|  | } | ||
|  | 
 | ||
|  | void i2c_init(void) { | ||
|  |     // set pull-up resistors on I2C bus pins
 | ||
|  |     PORTC |= 0b11; | ||
|  | 
 | ||
|  |     i2c_set_bitrate(400); | ||
|  | 
 | ||
|  |     // enable TWI (two-wire interface)
 | ||
|  |     TWCR |= (1 << TWEN); | ||
|  | 
 | ||
|  |     // enable TWI interrupt and slave address ACK
 | ||
|  |     TWCR |= (1 << TWIE); | ||
|  |     TWCR |= (1 << TWEA); | ||
|  | } | ||
|  | 
 | ||
|  | uint8_t i2c_start(uint8_t address) { | ||
|  |     // reset TWI control register
 | ||
|  |     TWCR = 0; | ||
|  | 
 | ||
|  |     // begin transmission and wait for it to end
 | ||
|  |     TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); | ||
|  |     while (!(TWCR & (1<<TWINT))); | ||
|  | 
 | ||
|  |     // check if the start condition was successfully transmitted
 | ||
|  |     if ((TWSR & 0xF8) != TW_START) { | ||
|  |         return 1; | ||
|  |     } | ||
|  | 
 | ||
|  |     // transmit address and wait
 | ||
|  |     TWDR = address; | ||
|  |     TWCR = (1<<TWINT) | (1<<TWEN); | ||
|  |     while (!(TWCR & (1<<TWINT))); | ||
|  | 
 | ||
|  |     // check if the device has acknowledged the READ / WRITE mode
 | ||
|  |     uint8_t twst = TW_STATUS & 0xF8; | ||
|  |     if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) { | ||
|  |         return 1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | void i2c_stop(void) { | ||
|  |     TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | ||
|  | } | ||
|  | 
 | ||
|  | uint8_t i2c_write(uint8_t data) { | ||
|  |     TWDR = data; | ||
|  | 
 | ||
|  |     // transmit data and wait
 | ||
|  |     TWCR = (1<<TWINT) | (1<<TWEN); | ||
|  |     while (!(TWCR & (1<<TWINT))); | ||
|  | 
 | ||
|  |     if ((TWSR & 0xF8) != TW_MT_DATA_ACK) { | ||
|  |         return 1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | uint8_t i2c_send(uint8_t address, uint8_t *data, uint16_t length) { | ||
|  |     if (i2c_start(address)) { | ||
|  |         return 1; | ||
|  |     } | ||
|  | 
 | ||
|  |     for (uint16_t i = 0; i < length; i++) { | ||
|  |         if (i2c_write(data[i])) { | ||
|  |             return 1; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     i2c_stop(); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } |