Files

217 lines
5.6 KiB
C

#include <stdio.h>
#include "ql_gpio.h"
#include "ql_rtos.h"
#include "ql_uart.h"
#include "ql_application.h"
#include "ql_type.h"
//#include "global_types.h"
#include "ql_func.h"
#define NO_ERROR 0
#define STATUS_FAIL -1
#define SW_I2C_CLOCK_PERIOD_USEC 10
#define DELAY_USEC (SW_I2C_CLOCK_PERIOD_USEC / 2)
/**
* Initialize all hard- and software components that are needed to set the
* SDA and SCL pins.
*/
void sw_i2c_init_pins(void) {
// IMPLEMENT
/*SDA*/
ql_gpio_init(GPIO_PIN_NO_50,PIN_DIRECTION_OUT,PIN_PULL_PU,PIN_LEVEL_HIGH);
/*SCL*/
ql_gpio_init(GPIO_PIN_NO_49,PIN_DIRECTION_OUT,PIN_PULL_PU,PIN_LEVEL_HIGH);
}
/**
* Release all resources initialized by sensirion_init_pins()
*/
void sw_i2c_release_pins(void) {
// IMPLEMENT or leave empty if no resources need to be freed
ql_gpio_deinit(GPIO_PIN_NO_49);
ql_gpio_deinit(GPIO_PIN_NO_50);
}
/**
* Configure the SDA pin as an input. With an external pull-up resistor the line
* should be left floating, without external pull-up resistor, the input must be
* configured to use the internal pull-up resistor.
*/
void sw_i2c_SDA_in(void) {
// IMPLEMENT
ql_gpio_deinit(GPIO_PIN_NO_50);
ql_gpio_init(GPIO_PIN_NO_50,PIN_DIRECTION_IN,PIN_PULL_DISABLE,PIN_LEVEL_HIGH);
}
/**
* Configure the SDA pin as an output and drive it low or set to logical false.
*/
void sw_i2c_SDA_out(void) {
// IMPLEMENT
ql_gpio_deinit(GPIO_PIN_NO_50);
ql_gpio_init(GPIO_PIN_NO_50,PIN_DIRECTION_OUT,PIN_PULL_DISABLE,PIN_LEVEL_LOW);
ql_gpio_set_level(GPIO_PIN_NO_50,PIN_LEVEL_LOW);
}
/**
* Read the value of the SDA pin.
* @returns 0 if the pin is low and 1 otherwise.
*/
uint8_t sw_i2c_SDA_read(void) {
// IMPLEMENT
PIN_LEVEL_E vv ;
ql_gpio_get_level(GPIO_PIN_NO_50,&vv);
return vv;
}
/**
* Configure the SCL pin as an input. With an external pull-up resistor the line
* should be left floating, without external pull-up resistor, the input must be
* configured to use the internal pull-up resistor.
*/
void sw_i2c_SCL_in(void) {
ql_gpio_deinit(GPIO_PIN_NO_49);
ql_gpio_init(GPIO_PIN_NO_49,PIN_DIRECTION_IN,PIN_PULL_DISABLE,PIN_LEVEL_HIGH);
}
/**
* Configure the SCL pin as an output and drive it low or set to logical false.
*/
void sw_i2c_SCL_out(void) {
// IMPLEMENT
ql_gpio_deinit(GPIO_PIN_NO_49);
ql_gpio_init(GPIO_PIN_NO_49,PIN_DIRECTION_OUT,PIN_PULL_DISABLE,PIN_LEVEL_LOW);
ql_gpio_set_level(GPIO_PIN_NO_49,PIN_LEVEL_LOW);
}
/**
* Read the value of the SCL pin.
* @returns 0 if the pin is low and 1 otherwise.
*/
uint8_t sw_i2c_SCL_read(void) {
PIN_LEVEL_E vv ;
ql_gpio_get_level(GPIO_PIN_NO_49,&vv);
return vv;
}
/**
* Sleep for a given number of microseconds. The function should delay the
* execution approximately, but no less than, the given time.
*
* The precision needed depends on the desired i2c frequency, i.e. should be
* exact to about half a clock cycle (defined in
* `SENSIRION_I2C_CLOCK_PERIOD_USEC` in `sensirion_arch_config.h`).
*
* Example with 400kHz requires a precision of 1 / (2 * 400kHz) == 1.25usec.
*
* @param useconds the sleep time in microseconds
*/
void sw_i2c_sleep_usec(u32 useconds) {
volatile uint_32 i;
for(i=0;i<useconds*100;i++)
i=i+1;
}
static int8 sw_i2c_wait_while_clock_stretching(void) {
/* Maximal timeout of 150ms (SCD30) in sleep polling cycles */
u32 timeout_cycles = 150000 / SW_I2C_CLOCK_PERIOD_USEC;
while (--timeout_cycles) {
if (sw_i2c_SCL_read())
return NO_ERROR;
sw_i2c_sleep_usec(SW_I2C_CLOCK_PERIOD_USEC);
}
return STATUS_FAIL;
}
int8 sw_i2c_write_byte(uint8_t data) {
int8 nack, i;
for (i = 7; i >= 0; i--) {
sw_i2c_SCL_out();
if ((data >> i) & 0x01)
sw_i2c_SDA_in();
else
sw_i2c_SDA_out();
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SCL_in();
sw_i2c_sleep_usec(DELAY_USEC);
if (sw_i2c_wait_while_clock_stretching())
return STATUS_FAIL;
}
sw_i2c_SCL_out();
sw_i2c_SDA_in();
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SCL_in();
if (sw_i2c_wait_while_clock_stretching())
return STATUS_FAIL;
nack = (sw_i2c_SDA_read() != 0);
sw_i2c_SCL_out();
return nack;
}
uint8_t sw_i2c_read_byte(uint8_t ack) {
int8 i;
uint8_t data = 0;
sw_i2c_SDA_in();
for (i = 7; i >= 0; i--) {
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SCL_in();
if (sw_i2c_wait_while_clock_stretching())
return 0xFF; // return 0xFF on error
data |= (sw_i2c_SDA_read() != 0) << i;
sw_i2c_SCL_out();
}
if (ack)
sw_i2c_SDA_out();
else
sw_i2c_SDA_in();
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SCL_in();
sw_i2c_sleep_usec(DELAY_USEC);
if (sw_i2c_wait_while_clock_stretching())
return 0xFF; // return 0xFF on error
sw_i2c_SCL_out();
sw_i2c_SDA_in();
return data;
}
int8 sw_i2c_start(void) {
sw_i2c_SCL_in();
if (sw_i2c_wait_while_clock_stretching())
return STATUS_FAIL;
sw_i2c_SDA_out();
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SCL_out();
sw_i2c_sleep_usec(DELAY_USEC);
return NO_ERROR;
}
void sw_i2c_stop(void) {
sw_i2c_SDA_out();
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SCL_in();
sw_i2c_sleep_usec(DELAY_USEC);
sw_i2c_SDA_in();
sw_i2c_sleep_usec(DELAY_USEC);
}
void sw_i2c_init(void) {
sw_i2c_init_pins();
sw_i2c_SCL_in();
sw_i2c_SDA_in();
}
void sw_i2c_release(void) {
sw_i2c_SCL_in();
sw_i2c_SDA_in();
sw_i2c_release_pins();
}