Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
I2C driver taken from PR #677, uncrustified, made functions static an…
…d added burst modes
- Loading branch information
Showing
3 changed files
with
495 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
/* | ||
* Copyright (c) 2015, Mehdi Migault | ||
* All rights reserved. | ||
* | ||
* 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. Neither the name of the copyright holder nor the names of its | ||
* contributors may be used to endorse or promote products derived | ||
* from this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT HOLDER OR CONTRIBUTORS 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. | ||
*/ | ||
/** | ||
* \addtogroup cc2538-i2c cc2538 I2C Control | ||
* @{ | ||
* | ||
* \file | ||
* Implementation file of the I2C Control module | ||
* | ||
* \author | ||
* Mehdi Migault | ||
*/ | ||
|
||
#include "i2c.h" | ||
|
||
#include <stdint.h> | ||
#include "clock.h" | ||
/*---------------------------------------------------------------------------*/ | ||
/* Additional functions */ | ||
static uint32_t | ||
get_sys_clock(void) | ||
{ | ||
/* Get the clock status diviser */ | ||
return SYS_CTRL_32MHZ / | ||
((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYS_DIV) + 1); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, | ||
uint32_t bus_speed) | ||
{ | ||
/* Enable I2C clock in different modes */ | ||
REG(SYS_CTRL_RCGCI2C) |= 1; /* Run mode */ | ||
|
||
/* Reset I2C peripheral */ | ||
REG(SYS_CTRL_SRI2C) |= 1; /* Reset position */ | ||
|
||
/* Delay for a little bit */ | ||
clock_delay_usec(50); | ||
|
||
REG(SYS_CTRL_SRI2C) &= ~1; /* Normal position */ | ||
|
||
/* Set pins in input */ | ||
GPIO_SET_INPUT(GPIO_PORT_TO_BASE(port_sda), GPIO_PIN_MASK(pin_sda)); | ||
GPIO_SET_INPUT(GPIO_PORT_TO_BASE(port_scl), GPIO_PIN_MASK(pin_scl)); | ||
|
||
/* Set peripheral control for the pins */ | ||
GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(port_sda), GPIO_PIN_MASK(pin_sda)); | ||
GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(port_scl), GPIO_PIN_MASK(pin_scl)); | ||
|
||
/* Set the pad to no drive type */ | ||
ioc_set_over(port_sda, pin_sda, IOC_OVERRIDE_DIS); | ||
ioc_set_over(port_scl, pin_scl, IOC_OVERRIDE_DIS); | ||
|
||
/* Set pins as peripheral inputs */ | ||
REG(IOC_I2CMSSDA) = ioc_input_sel(port_sda, pin_sda); | ||
REG(IOC_I2CMSSCL) = ioc_input_sel(port_scl, pin_scl); | ||
|
||
/* Set pins as peripheral outputs */ | ||
ioc_set_sel(port_sda, pin_sda, IOC_PXX_SEL_I2C_CMSSDA); | ||
ioc_set_sel(port_scl, pin_scl, IOC_PXX_SEL_I2C_CMSSCL); | ||
|
||
/* Enable the I2C master module */ | ||
i2c_master_enable(); | ||
|
||
/* t the master clock frequency */ | ||
i2c_set_frequency(bus_speed); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_master_enable(void) | ||
{ | ||
REG(I2CM_CR) |= 0x10; /* Set MFE bit */ | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_master_disable(void) | ||
{ | ||
REG(I2CM_CR) &= ~0x10; /* Reset MFE bit */ | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_set_frequency(uint32_t freq) | ||
{ | ||
/* Peripheral clock setting, using the system clock */ | ||
REG(I2CM_TPR) = ((get_sys_clock() + (2 * 10 * freq) - 1) / | ||
(2 * 10 * freq)) - 1; | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_master_set_slave_address(uint8_t slave_addr, uint8_t access_mode) | ||
{ | ||
if(access_mode) { | ||
REG(I2CM_SA) = ((slave_addr << 1) | 1); | ||
} else { | ||
REG(I2CM_SA) = (slave_addr << 1); | ||
} | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_master_data_put(uint8_t data) | ||
{ | ||
REG(I2CM_DR) = data; | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_master_data_get(void) | ||
{ | ||
return REG(I2CM_DR); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
void | ||
i2c_master_command(uint8_t cmd) | ||
{ | ||
REG(I2CM_CTRL) = cmd; | ||
/* Here we need a delay, otherwise the I2C module keep the receiver mode */ | ||
clock_delay_usec(1); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_master_busy(void) | ||
{ | ||
return REG(I2CM_STAT) & I2CM_STAT_BUSY; | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_master_error(void) | ||
{ | ||
uint8_t temp = REG(I2CM_STAT); /* Get all status */ | ||
if(temp & I2CM_STAT_BUSY) { /* No valid if BUSY bit is set */ | ||
return I2C_MASTER_ERR_NONE; | ||
} else if(temp & (I2CM_STAT_ERROR | I2CM_STAT_ARBLST)) { | ||
return temp; /* Compare later */ | ||
} | ||
return I2C_MASTER_ERR_NONE; | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_single_send(uint8_t slave_addr, uint8_t data) | ||
{ | ||
i2c_master_set_slave_address(slave_addr, I2C_SEND); | ||
i2c_master_data_put(data); | ||
i2c_master_command(I2C_MASTER_CMD_SINGLE_SEND); | ||
|
||
while(i2c_master_busy()); | ||
|
||
/* Return the STAT register of I2C module if error occured, I2C_MASTER_ERR_NONE otherwise */ | ||
return i2c_master_error(); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_single_receive(uint8_t slave_addr, uint8_t *data) | ||
{ | ||
uint32_t temp; | ||
|
||
i2c_master_set_slave_address(slave_addr, I2C_RECEIVE); | ||
i2c_master_command(I2C_MASTER_CMD_SINGLE_RECEIVE); | ||
|
||
while(i2c_master_busy()); | ||
temp = i2c_master_error(); | ||
if(temp == I2C_MASTER_ERR_NONE) { | ||
*data = i2c_master_data_get(); | ||
} | ||
return temp; | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len) | ||
{ | ||
uint8_t sent; | ||
if((len == 0) || (data == NULL)) { | ||
return I2CM_STAT_INVALID; | ||
} | ||
if(len == 1) { | ||
return i2c_single_send(slave_addr, data[0]); | ||
} | ||
i2c_master_set_slave_address(slave_addr, I2C_SEND); | ||
i2c_master_data_put(data[0]); | ||
i2c_master_command(I2C_MASTER_CMD_BURST_SEND_START); | ||
while(i2c_master_busy()); | ||
if(i2c_master_error() == I2C_MASTER_ERR_NONE) { | ||
for(sent = 1; sent <= (len - 2); sent++) { | ||
i2c_master_data_put(data[sent]); | ||
i2c_master_command(I2C_MASTER_CMD_BURST_SEND_CONT); | ||
while(i2c_master_busy()); | ||
} | ||
/* This should be the last byte, stop sending */ | ||
i2c_master_data_put(data[len - 1]); | ||
i2c_master_command(I2C_MASTER_CMD_BURST_SEND_FINISH); | ||
while(i2c_master_busy()); | ||
} | ||
|
||
/* Return the STAT register of I2C module if error occurred, I2C_MASTER_ERR_NONE otherwise */ | ||
return i2c_master_error(); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
uint8_t | ||
i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len) | ||
{ | ||
uint8_t recv = 0; | ||
if((len == 0) || data == NULL) { | ||
return I2CM_STAT_INVALID; | ||
} | ||
if(len == 1) { | ||
return i2c_single_receive(slave_addr, &data[0]); | ||
} | ||
i2c_master_set_slave_address(slave_addr, I2C_RECEIVE); | ||
i2c_master_command(I2C_MASTER_CMD_BURST_RECEIVE_START); | ||
while(i2c_master_busy()); | ||
if(i2c_master_error() == I2C_MASTER_ERR_NONE) { | ||
data[0] = i2c_master_data_get(); | ||
/* If we got 2 or more bytes pending to be received, keep going*/ | ||
for(recv = 1; recv <= (len - 2); recv++) { | ||
i2c_master_command(I2C_MASTER_CMD_BURST_RECEIVE_CONT); | ||
while(i2c_master_busy()); | ||
data[recv] = i2c_master_data_get(); | ||
} | ||
/* This should be the last byte, stop receiving */ | ||
i2c_master_command(I2C_MASTER_CMD_BURST_RECEIVE_FINISH); | ||
while(i2c_master_busy()); | ||
data[len - 1] = i2c_master_data_get(); | ||
} | ||
return i2c_master_error(); | ||
} | ||
/*---------------------------------------------------------------------------*/ | ||
/** @} */ |
Oops, something went wrong.