Skip to content
Snippets Groups Projects
Commit 248348b5 authored by Sergi Hernandez's avatar Sergi Hernandez
Browse files

Added an i2c peripheral implementation and a basic compass module.

parent bdafec94
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,7 @@ PROJECT=bioloid_exp
########################################################
# afegir tots els fitxers que s'han de compilar aquí
########################################################
SOURCES=src/main.c src/dyn_slave_se.c src/dyn_slave_diff.c src/mem.c src/dyn_common.c src/ports.c src/adc.c src/pwm.c src/dac.c
SOURCES=src/main.c src/dyn_slave_se.c src/dyn_slave_diff.c src/mem.c src/dyn_common.c src/ports.c src/adc.c src/pwm.c src/dac.c src/i2c.c src/compass.c
OBJS=$(SOURCES:.c=.o)
SRC_DIR=./src/
INCLUDE_DIR=./include/
......
#ifndef _COMPASS_H
#define _COMPASS_H
#include <avr/io.h>
#include <avr/interrupt.h>
// compass address
#define COMPASS_ADDR 0x42
// compass commands
#define COMPASS_HEADING 0x41
#define COMPASS_START_CAL 0x43
#define COMPASS_STOP_CAL 0x45
void compass_init(void);
void compass_start(void);
void compass_stop(void);
void compass_start_calibration(void);
void compass_stop_calibration(void);
void compass_loop(void);
#endif
#ifndef I2C_H
#define I2C_H
// TWSR values (not bits)
// (taken from avr-libc twi.h - thank you Marek Michalkiewicz)
// Master
#define TW_START 0x08
#define TW_REP_START 0x10
// Master Transmitter
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
// Master Receiver
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
// Misc
#define TW_NO_INFO 0xF8
#define TW_BUS_ERROR 0x00
// defines and constants
#define TWCR_CMD_MASK 0x0F
#define TWSR_STATUS_MASK 0xF8
// return values
#define I2C_OK 0x00
#define I2C_ERROR_NODEV 0x01
// types
typedef enum {I2C_IDLE=0,I2C_BUSY=1,I2C_MASTER_TX=2,I2C_MASTER_RX=3} i2c_states_t;
/* public functions */
void i2c_init(uint16_t bitrate_khz);
void i2c_set_bitrate(uint16_t bitrate_khz);
void i2c_master_send(uint8_t deviceAddr, uint8_t length, uint8_t *data);
void i2c_master_receive(uint8_t deviceAddr, uint8_t length);
void i2c_get_data(unsigned char length, unsigned char *data);
i2c_states_t i2c_get_state(void);
#endif
......@@ -160,7 +160,10 @@
#define DAC_CH0_VOLTAGE_H 0x81
#define DAC_CH1_VOLTAGE_L 0x82
#define DAC_CH1_VOLTAGE_H 0x83
#define COMPASS_CONTROL 0x84
#define COMPASS_HEADING_VAL 0x85
#define COMPASS_AVG_HEADING_VAL 0x86
#define RAM_SIZE 132
#define RAM_SIZE 135
#endif
......@@ -17,6 +17,8 @@ volatile int16_t adc_data[NUM_CH];
volatile int16_t adc_ch_data[NUM_CH][MAX_NUM_SAMPLES];
volatile uint8_t adc_current_sample;
volatile uint8_t adc_num_samples;
volatile uint8_t adc_running;
volatile uint8_t adc_prescaler_mask;
/* private functions */
void adc_set_channel(uint8_t ch_id)
......@@ -62,10 +64,12 @@ void adc_init(void)
// set the initial channel to convert
adc_current_ch=0;
adc_current_sample=0;
adc_running=0;
adc_num_samples=MAX_NUM_SAMPLES;
ram_data[ADC_NUM_SAMPLES]=MAX_NUM_SAMPLES;
adc_sample_period_ms=0x01;
ram_data[ADC_SAMPLE_PERIOD]=0x01;
adc_set_sample_period(adc_sample_period_ms);
// configure the timer 2 to perform periodic conversions (1 ms period)
TCCR2=(1<<WGM21);// CTC mode, no output, prescaler to 0 (no clock source)
......@@ -84,6 +88,7 @@ void adc_start(void)
TIFR|=(1<<OCF2);
TIFR|=(1<<TOV2);
// configure the timer prescaler and count value
adc_running=0x01;
adc_set_sample_period(adc_sample_period_ms);
ram_data[ADC_CONTROL]|=0x02;
}
......@@ -93,6 +98,7 @@ void adc_stop(void)
TCCR2&=0xF8;// set prescaler to 0 (no clock source)
// disable the ADC
ADCSRA&=~(1<<ADEN);
adc_running=0x00;
ram_data[ADC_CONTROL]&=0xFD;
}
......@@ -123,8 +129,13 @@ void adc_set_sample_period(uint8_t time_ms)
if(compare_value<256)
{
OCR2=(uint8_t)compare_value;
TCCR2&=0xF8;
TCCR2|=(i+2);
if(adc_running)
{
TCCR2&=0xF8;
TCCR2|=(i+1);
}
else
adc_prescaler_mask=i+1;
break;
}
}
......@@ -134,7 +145,6 @@ void adc_loop(void)
{
uint8_t i;
uint16_t data;
static int count=1000;
if(adc_is_period_done())
{
......@@ -149,12 +159,6 @@ void adc_loop(void)
{
if(adc_is_conversion_done())
{
count--;
if(count==0)
{
count=1000;
toggle_led();
}
ADCSRA|=(1<<ADIF);// clear interrupt flag
data=(ADCL | (ADCH<<8));
ram_data[ADC_CHANNEL0_L+adc_current_ch*2]=data%256;
......
#include "compass.h"
#include "i2c.h"
#include "mem.h"
#include "ports.h"
/* private variables */
volatile uint16_t compass_heading;
volatile uint16_t compass_heading_averaged;
volatile uint8_t compass_waiting_data;
volatile uint8_t compass_calibrated;
volatile uint8_t compass_calibrating;
volatile uint8_t compass_stopping;
volatile uint8_t compass_stopped;
volatile uint8_t compass_delay_done;
/* private functions */
void compass_avrg(uint16_t heading)
{
static unsigned long int new_average,first_value;
static uint8_t num_data=0;
unsigned long int diff=0;
if(num_data==0)
{
num_data=num_data+1;
first_value=(long int)heading;
}
else
{
diff=heading+3600-first_value;
if(diff<1800)
diff=diff+3600;
else if(diff>5400)
diff=diff-3600;
new_average=new_average+diff;
num_data=num_data+1;
if(num_data==17)
{
new_average=new_average/16;
new_average=new_average+first_value;
compass_heading_averaged=(uint16_t)new_average;
if(compass_heading_averaged>3600)
compass_heading_averaged=compass_heading_averaged-3600;
new_average=0;
num_data=0;
}
}
}
void compass_start_time_delay(uint8_t delay_ms)
{
TCNT0=0x00;// reset counter
OCR0=delay_ms*16;// set count value
TCCR0&=0xF8;
TCCR0|=0x07;// enable clock
compass_delay_done=0x00;
}
uint8_t compass_is_delay_done(void)
{
return compass_delay_done;
}
/* interrupt handlers */
ISR(TIMER0_COMP_vect)
{
compass_delay_done=0x01;
// disable clock
TCCR0&=0xF8;
}
/* public functions */
void compass_init(void)
{
/* initialize private variables */
compass_calibrated=0x00;
compass_calibrating=0x00;
compass_stopped=0x01;
compass_stopping=0x00;
compass_waiting_data=0x00;
compass_heading=0;
compass_heading_averaged=0;
compass_delay_done=0x00;
/* use timer 0 to control the operation delay */
TCCR0=(1<<WGM01);//campare mode, output disable, prescaler 0
ASSR=0x00;// disable assynchronous operation
TIMSK=(1<<OCIE0);// enable interrupts
OCR0=0xFF;
TCNT0=0x00;
/* initialize i2c peripheral */
i2c_init(100);
}
void compass_start(void)
{
compass_stopping=0x00;
compass_stopped=0x00;
compass_waiting_data=0x00;
ram_data[COMPASS_CONTROL]|=0x04;
}
void compass_stop(void)
{
compass_stopping=0x01;
}
void compass_start_calibration(void)
{
}
void compass_stop_calibration(void)
{
}
void compass_loop(void)
{
uint8_t cmd,heading[2];
if(compass_stopped==0x00)// compass is running
{
if(i2c_get_state()==I2C_IDLE)// the last I2C command has terminated
{
if(compass_waiting_data==0x01)// we are waiting heading data
{
if(compass_is_delay_done()==0x01)// the required time from the command has elapsed
{
i2c_get_data(2,heading);
compass_heading=heading[1]+(heading[0]<<8);
compass_avrg(compass_heading);
compass_waiting_data=0x00;
toggle_led();
}
}
else
{
if(compass_stopping==0x00)
{
cmd=COMPASS_HEADING;
i2c_master_send(COMPASS_ADDR,1,&cmd);
compass_waiting_data=0x01;
compass_start_time_delay(10);
}
else
{
compass_stopping=0x00;
compass_stopped=0x00;
ram_data[COMPASS_CONTROL]&=0xFB;
}
}
}
}
}
/*void compass_periodic_call(void)
{
uint8_t cmd,heading[2];
static int count=0;
if(i2cGetState()==I2C_IDLE)
{
if(compass_waiting_data)
{
if(compass_calibrate)
{
compass_calibrating=TRUE;
compass_calibrate=FALSE;
count=100;
}
else if(compass_calibrating)
{
if(count>0)
count--;
else
{
cmd=COMPASS_START_CAL;
i2cMasterSend(COMPASS_ADDR, 1, &cmd);
compass_waiting_data=FALSE;
}
}
else
{
if(count>0)
count--;
else
{
i2c_get_data(2,heading);
compass_heading=heading[1]+(heading[0]<<8);
compass_avrg(compass_heading);
cmd=COMPASS_HEADING;
i2cMasterSend(COMPASS_ADDR, 1, &cmd);
compass_waiting_data=FALSE;
count = 10;
}
}
}
else
{
if(compass_calibrating)
{
count++;
if(count==30000)
{
cmd=COMPASS_STOP_CAL;
i2cMasterSend(COMPASS_ADDR, 1, &cmd);
compass_waiting_data=TRUE;
compass_calibrate=FALSE;
compass_calibrating=FALSE;
count = 100;
}
}
else
{
if(count>0)
count--;
else
{
i2cMasterReceive(COMPASS_ADDR,2);
compass_waiting_data=TRUE;
}
}
}
}
}*/
src/i2c.c 0 → 100644
#include <avr/io.h>
#include <avr/interrupt.h>
#include "i2c.h"
#define I2C_RX_BUFFER_LEN 32
#define I2C_TX_BUFFER_LEN 32
/* private variables */
static volatile i2c_states_t i2c_state;
static uint8_t i2c_device_address;
// send/transmit buffer (outgoing data)
static uint8_t i2c_tx_data[I2C_RX_BUFFER_LEN];
static uint8_t i2c_tx_data_ptr;
static uint8_t i2c_tx_length;
// receive buffer (incoming data)
static uint8_t i2c_rx_data[I2C_TX_BUFFER_LEN];
static uint8_t i2c_rx_data_ptr;
static uint8_t i2c_rx_length;
/* private functions */
inline void i2c_send_start(void)
{
// send start condition
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT)|(1<<TWSTA);
}
inline void i2c_send_stop(void)
{
// transmit stop condition
// leave with TWEA on for slave receiving
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
}
inline void i2c_wait_for_complete(void)
{
// wait for i2c interface to complete operation
while((TWCR&(1<<TWINT))==0x00);
}
inline void i2c_send_byte(uint8_t data)
{
// save data to the TWDR
TWDR=data;
// begin send
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT);
}
inline void i2c_receive_byte(uint8_t ackFlag)
{
// begin receive over i2c
if( ackFlag )
{
// ackFlag = TRUE: ACK the recevied data
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT)|(1<<TWEA);
}
else
{
// ackFlag = FALSE: NACK the recevied data
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT);
}
}
inline uint8_t i2c_get_byte(void)
{
// retieve received data byte from i2c TWDR
return TWDR;
}
i2c_states_t i2c_get_state(void)
{
// retieve current i2c status from i2c TWSR
return i2c_state;
}
/* interrupt handlers */
ISR(TWI_vect)
{
// read status bits
uint8_t status = TWSR&TWSR_STATUS_MASK;
switch(status)
{
// Master General
case TW_START://0x08: Sent start condition
case TW_REP_START:// 0x10: Sent repeated start condition
// send device address
i2c_send_byte(i2c_device_address);
break;
// Master Transmitter & Receiver status codes
case TW_MT_SLA_ACK:// 0x18: Slave address acknowledged
case TW_MT_DATA_ACK:// 0x28: Data acknowledged
if(i2c_tx_data_ptr < i2c_tx_length)
{
// send data
i2c_send_byte( i2c_tx_data[i2c_tx_data_ptr++] );
}
else
{
// transmit stop condition, enable SLA ACK
i2c_send_stop();
// set state
i2c_state = I2C_IDLE;
}
break;
case TW_MR_DATA_NACK:// 0x58: Data received, NACK reply issued
// store final received data byte
i2c_rx_data[i2c_rx_data_ptr++] = TWDR;
// continue to transmit STOP condition
case TW_MR_SLA_NACK:// 0x48: Slave address not acknowledged
case TW_MT_SLA_NACK:// 0x20: Slave address not acknowledged
case TW_MT_DATA_NACK:// 0x30: Data not acknowledged
// transmit stop condition, enable SLA ACK
i2c_send_stop();
// set state
i2c_state = I2C_IDLE;
break;
case TW_MT_ARB_LOST:// 0x38: Bus arbitration lost
// release bus
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT);
// set state
i2c_state = I2C_IDLE;
break;
case TW_MR_DATA_ACK:// 0x50: Data acknowledged
// store received data byte
i2c_rx_data[i2c_rx_data_ptr++] = TWDR;
// fall-through to see if more bytes will be received
case TW_MR_SLA_ACK:// 0x40: Slave address acknowledged
if(i2c_rx_data_ptr < (i2c_rx_length-1))
// data byte will be received, reply with ACK (more bytes in transfer)
i2c_receive_byte(0x01);
else
// data byte will be received, reply with NACK (final byte in transfer)
i2c_receive_byte(0x00);
break;
// Misc
case TW_NO_INFO:// 0xF8: No relevant state information
// do nothing
break;
case TW_BUS_ERROR:// 0x00: Bus error due to illegal start or stop condition
// reset internal hardware and release bus
TWCR=(TWCR&TWCR_CMD_MASK)|(1<<TWINT)|(1<<TWSTO)|(1<<TWEA);
// set state
i2c_state = I2C_IDLE;
break;
}
}
/* public functions */
void i2c_init(uint16_t bitrate_khz)
{
/* configure the io ports */
//DDRD|=0x03;
// set i2c bit rate to 100KHz
i2c_set_bitrate(bitrate_khz);
/* initialize the internal variables */
i2c_tx_data_ptr=0;
i2c_tx_length=0;
i2c_rx_data_ptr=0;
i2c_rx_length=0;
i2c_state=I2C_IDLE;
TWCR=(1<<TWEN)|(1<<TWIE)|(1<<TWEA);
}
void i2c_set_bitrate(uint16_t bitrate_khz)
{
uint8_t bitrate_div;
TWSR&=~((1<<TWPS0)|(1<<TWPS1));
// calculate bitrate division
bitrate_div = ((F_CPU/1000l)/bitrate_khz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
TWBR=bitrate_div;
}
void i2c_master_send(uint8_t deviceAddr, uint8_t length, uint8_t* data)
{
uint8_t i;
// wait for interface to be ready
while(i2c_state);
// set state
i2c_state = I2C_MASTER_TX;
// save data
i2c_device_address = (deviceAddr & 0xFE); // RW cleared: write operation
for(i=0; i<length; i++)
i2c_tx_data[i] = *data++;
i2c_tx_data_ptr = 0;
i2c_tx_length = length;
// send start condition
i2c_send_start();
}
void i2c_master_receive(uint8_t deviceAddr, uint8_t length)//, uint8_t* data)
{
// uint8_t i;
// wait for interface to be ready
while(i2c_state);
// set state
i2c_state = I2C_MASTER_RX;
// save data
i2c_device_address = (deviceAddr|0x01); // RW set: read operation
i2c_rx_data_ptr = 0;
i2c_rx_length = length;
// send start condition
i2c_send_start();
}
void i2c_get_data(unsigned char length, unsigned char *data)
{
unsigned char i;
for(i=0;i<length;i++)
data[i]=i2c_rx_data[i];
}
......@@ -8,6 +8,7 @@
#include "adc.h"
#include "pwm.h"
#include "dac.h"
#include "compass.h"
int16_t main(void)
{
......@@ -16,13 +17,17 @@ int16_t main(void)
dyn_slave_diff_init(ram_data[Baud_Rate],ram_data[ID]);
init_ports();
adc_init();
// pwm_init();
// dac_init();
pwm_init();
dac_init();
compass_init();
sei();
compass_start();
while (1)
{
adc_loop();
compass_loop();
dyn_slave_se_loop();
dyn_slave_diff_loop();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment