Skip to content

Commit

Permalink
This commit allows the user to communicate with I2C slaves devices. I…
Browse files Browse the repository at this point in the history
…t consists of a soft i2c core along with a shift register and an examples directory to show its usage.
  • Loading branch information
Roarin committed Jul 8, 2016
1 parent 0ddd377 commit 1b6d3a8
Show file tree
Hide file tree
Showing 6 changed files with 817 additions and 1 deletion.
15 changes: 15 additions & 0 deletions examples/download.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash -e

DEVS=$(lsusb|grep -E '(2a19|16c0|04b4|1d50|fb9a|1443)' |sed 's/:.*//;s/Bus //;s/Device //;s/ /\//')

if [ -z "$1" ]; then
echo "$0: usage: $0 <file>"
exit 1;
fi

for dev in $DEVS;do
echo "Downloading $1 to $dev"
/sbin/fxload -D /dev/bus/usb/$dev -t fx2lp -I $1
done

exit 0
11 changes: 11 additions & 0 deletions examples/i2c_bitbang/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FX2LIBDIR=../../
BASENAME = i2c_main
SOURCES=i2c_main.c
CODE_SIZE = --code-size 0x3000
XRAM_LOC = --xram-loc 0x3200
XRAM_SIZE = --xram-size 0x700
DSCR_AREA=
INT2JT=
include $(FX2LIBDIR)/lib/fx2.mk
fx2_download:
../download.sh build/$(BASENAME).ihx
176 changes: 176 additions & 0 deletions examples/i2c_bitbang/i2c_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* Copyright (C) 2009 Ubixum, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**/
#include <stdio.h>
#include <fx2regs.h>
#include <fx2macros.h>
#include <delay.h>
#include <fx2ints.h>
#include <i2c/i2c_utils.h>

//DELETE once merged.
void fast_uart(BYTE a);


/**************************************************
I2C declarations
***************************************************/
//Buffer to load up the data and insert into
//the i2c_client queue
__xdata unsigned char write_addr[I2C_ADDR];
//This is the data buffer.
__xdata unsigned char write_data[I2C_DATA];
//This is the address length
__xdata unsigned char rx_addr_length;
//This is the data length which needs to be read from or written to.
__xdata unsigned char rx_data_length;
//Implementation specific. Not needed for all examples. Used here
//to read and write from different address locations.
__xdata unsigned char wr_addr;


void main() {
SETCPUFREQ(CLK_48M);
EA = 1; // global interrupt enable
/********************************
I2C BLOCK BITBANG
*********************************/
//Called with number of retries
i2c_init(3);
configure_start_timer();
ENABLE_TIMER1();
wr_addr = 0x03;
while (TRUE)
{

write_addr[0] = 0xa0;
write_addr[1] = 0x00;
write_addr[2] = wr_addr;
write_data[0] = 0x44;
//Address, data, address length and data length
I2CPutTX(&write_addr[0],&write_data[0],0x03,0x01);
//i2c_control();
write_addr[0] = 0xa1;
write_data[0] = 0x34;
I2CPutRXRead(&write_addr[0],0x01,0x01);
I2CGetRXData(&write_addr[0],&write_data[0]);
fast_uart(data[0]);
i2c_control();
if(wr_addr == 0x00)
{
wr_addr = 0x03;
}
else
{
wr_addr--;
}
}
}

void timer1_isr ()
__interrupt TF1_ISR
{
__asm
mov a,_tx_rx //(2 cycles. Move the state into the accumulator.)
CJNE A, #0x02, state //(4 cycles. If in halt state, do nothing.)
ajmp finish //(3 cycles. Return from ISR if buffer is not ready to shift the data out.)
state:
djnz _bit_count,cont; //(4 cycles. This is sued to keep track of the number of data bytes which need to be shifted out.)
mov _tx_rx,#0x02 //(3 cycles. Set our current status to busy so nothing else can interrupt us till we shift data in or out.)
ajmp finish //(3 cycles. If data has been shifted, but has not been read, then jump to finish.)
cont:
orl _OEA,#0x40 //(3 cycles. First always set out clock pin direction. This is needed as discussed already in comments.)
clr _PA6 //(2 cycles. Set the SCL line low.)
mov a,_tx_rx //(2 cycles. Move the state back into the accumulator.)
CJNE A, #0x00, rx //(4 cycles. Check if we are in RX or TX mode.)
tx:
orl _OEA,#0x80 //(3 cycles. We are in TX mode. Set the SDA direction.)
mov a, _tx_i2c_buffer //(2 cycles. Move the data which needs to be transmitted into the accumulator.)
rlc a //(1 cycles. Rotate and move the bit which needs to be sent out into the carry.)
mov _PA7, c //(2 cycles. Move the data into the SDA pin.)
mov _tx_i2c_buffer,a //(2 cycles. Now move the data back so that the next rotate can be performed when the ISR executes.)
sjmp sclh //(3 cycles. Jump to toggle SCL now.)
rx:
anl _OEA,#0x7f //(3 cycles. Set the mode of SDA pin again.)
mov a, _tx_i2c_buffer //(2 cycles. Move data received into accumulator.)
mov c,_PA7 //(2 cycles. Move the SDA line value into the carry. Delay has already been introduced between setting clock low and reading the first bit of data. Otherwise, follow the MPSSE i2c routine.)
rlc a //(1 cycle. Since the next bit will be received in the same ISR we need to shift the data.)
mov _tx_i2c_buffer,a //(2 cycles. Move the data back into accumulator for next ISR execution routine)
nop //(1 cycle. Wait for 1 cycle before setting the bit high again.)
sclh:
setb _PA6 //(2 cycles. Set the SCL high)
finish:
nop
__endasm;
}

/**************************
Will be DELETED once the pull requests are merged
**************************/
void fast_uart(BYTE a) {
OEA |= 0x04;
//An efficient UART bitbang routine in assembly
__asm
//Like #define in C. Can easily be used to change the pin
.equ TX_PIN, _PA2
//Disable interrupts
clr _EA
//Move the data to be sent into the ACC
mov a , dpl
//Clear carry
clr c
//We need to send out 8 bits of data
//Load r0 with value 8
mov r0, #0x08;
//Create the start bit
clr TX_PIN;
//Precalculated delay since 1 cycle takes 88.33ns
//Mov takes 2 cycles
mov r1, #0x22;
0006$:
//DJNZ on Rn takes 3 cycle. This waits for
//23*3, 69 cycles
//71 cycle delay
djnz r1, 0006$;
//Add 2 more cycles of delay
//97 cycles
nop;
nop;
0001$:
//2 cycles
rrc a;
//Move the carry into the port
mov _PA2, c
//Now we need to add delay for the next
//2 cycles of delay
mov r1, #0x1F;
//31*3 , 93 cycles of delay
0004$:
djnz r1, 0004$;
//1 more cycle, now upto 94
nop;
//3 more cycles of delay
//97 cycles
djnz r0, 0001$;
setb _PA2;
mov r1, #0x80;
0005$:
djnz r1, 0005$;
nop
setb _EA;
__endasm;
}
93 changes: 93 additions & 0 deletions include/i2c/i2c_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#ifndef I2C_UTILS_
#define I2C_UTILS_

#include "fx2regs.h"
#include "fx2types.h"

#define I2C_ELEMENTS 5
#define I2C_DATA 5
#define I2C_ADDR 5
#define I2C_SIZE (I2C_ELEMENTS + 1)
#define SCL PA6
#define SDA PA7
#define SYNCDELAY SYNCDELAY4

//Structure for writing the I2C data onto SDA and SCL
struct i2c_client
{
//Address
unsigned short addr[I2C_ADDR];
//Upto 5 data bytes can be written
BYTE data[I2C_DATA];
//The length of data to write to I2C lines
//Does not include the address byte
BYTE data_length;
BYTE addr_length;
};

//Structure for reading data from I2C device.
struct i2c_client_read
{
//Address
unsigned short addr[I2C_ADDR];
//The length of data to write to I2C lines
//Does not include the address byte
BYTE data_length;
BYTE addr_length;
};
__bit I2CPutTX(BYTE * addr, BYTE * data, BYTE addr_length, BYTE data_length);
__bit I2CPutRXRead(BYTE * addr, BYTE addr_length, BYTE data_length);
__bit I2CGetRXRead();
__bit I2CCheckRXRead();
__bit I2CPutRXData(BYTE * addr, BYTE * data, BYTE addr_length, BYTE data_length);
__bit I2CGetRXData(BYTE * addr, BYTE * data);
__bit I2CCheckRXData();
__bit I2CGetTX();
__bit I2CCheckTX();
void i2c_init(BYTE retry);
void i2c_control();
void configure_start_timer();



/*************************
I2C Controller
*************************/

enum isr_state
{
state_tx = 0, //0
state_rx = 1 , //1
state_wait = 2
};
enum i2c_states
{
idle = 0,
start = 1,
address = 2,
addr_ack = 3,
data_write = 4,
data_write_ack = 5,
data_read = 6,
data_read_ack = 7,
stop = 8,
read_addr_ack = 9,
read_data_ack = 10,
};
extern enum isr_state tx_rx;
extern BYTE bit_count;
extern BYTE tx_i2c_buffer;
//Variable declarations for address and data
extern __xdata BYTE addr[I2C_ADDR];
extern __xdata BYTE data[I2C_DATA];
extern __xdata BYTE length;
extern __xdata BYTE retries;
/****************************************
Cant pass so many arguments in a function
*****************************************/
extern __xdata BYTE write_addr[I2C_ADDR];
extern __xdata BYTE write_data[I2C_DATA];
extern __xdata BYTE rx_addr_length;
extern __xdata BYTE rx_data_length;
extern __xdata BYTE wr_addr;
#endif
2 changes: 1 addition & 1 deletion lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

AS8051?=sdas8051
SOURCES = serial.c i2c.c delay.c setupdat.c gpif.c eputils.c $(wildcard interrupts/*.c)
SOURCES = serial.c i2c.c delay.c setupdat.c gpif.c eputils.c $(wildcard interrupts/*.c) $(wildcard i2c/*.c)
FX2_OBJS = $(patsubst %.c,%.rel, $(SOURCES)) usbav.rel
INCLUDES = -I../include
SDCC = sdcc -mmcs51 $(SDCCFLAGS)
Expand Down
Loading

0 comments on commit 1b6d3a8

Please sign in to comment.