This code is from project: Many EEPROMs inside of one / inject additional bits into I2C bus
Makefile
CPU=attiny45 GCC=avr-gcc CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min INCLUDES= LIBS= OBJCPY=avr-objcopy OBJECTS=main.o delay.o PROJECT_NAME=i2c_injector HEX_FILE=$(PROJECT_NAME).hex HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex PROG=avrdude PROG_FLAGS=-V -c usbasp -p $(CPU) all: cls $(PROJECT_NAME) obj size #upload $(PROJECT_NAME): $(OBJECTS) $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES) main.o: main.c main.h $(GCC) $(CFLAGS) $(INCLUDES) -c main.c delay.o: delay.c delay.h $(GCC) $(CFLAGS) $(INCLUDES) -c delay.c obj: $(OBJECTS) $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE) clean: rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE) cls: clear size: du -b $(HEX_FILE) upload: all $(HEX_FILE) $(PROG) $(PROG_FLAGS) -e -U flash:w:$(HEX_FILE) download: $(PROG) $(PROG_FLAGS) -U flash:r:$(HEX_FILE_DUMP) reset: $(PROG) $(PROG_FLAGS)
delay.c
#include "main.h"
#include <util/delay.h>
#include "delay.h"
/****************************************************************************/
/* It is better to put a delay in the loop than provide high value to */
/* standard function, because the code will be smaller, */
/****************************************************************************/
void delay_ms(unsigned short ms) {
while ( ms ) {
ms--;
_delay_ms(1);
}
}
void delay_us(unsigned short us) {
while ( us ) {
us--;
_delay_us(1);
}
}
delay.h
#ifndef _H_DELAY_
#define _H_DELAY_
#define nop() __asm__ __volatile__("nop")
void delay_ms(unsigned short ms);
void delay_us(unsigned short us);
#endif
main.h
#ifndef _H_MAIN_H #define _H_MAIN_H // define CPU speed, in our case is up to 16Mhz from internal PLL // this is for delay mostly so even if on 3.3v we would have lower clock // than 16Mhz, we use delay in one place only and it's not so critical // to have slightly smaller/larger time there #define F_CPU 16000000L // some usefeuul macros #define H(a,b) a |=(1<<(b)) #define L(a,b) a &=~(1<<(b)) #define IS(a,b) bit_is_set(a,b) #define BS(a,b) (a & (1<<(b))) #endif
main.c
#include "main.h"
#include "delay.h"
#include <avr/io.h>
#include <avr/interrupt.h> // sei
// depends of memory used 3 is for at24c256
// 7 will be for at24c512
#define MAX_BITS 3
uint8_t clk = 0;
uint8_t start = 0;
uint8_t bits = 0b000;
SIGNAL(INT0_vect) { // SDA
// check if start condition is met
if(BS(PINB, PB1)) {
start = 1;
clk = 0;
// make sure the WP is low at this time
L(PORTB, PB0);
}
}
SIGNAL(PCINT0_vect) { // SCL
// start == 1 means that we have seen start condition
// now, start processing
if (start) {
switch(clk) {
case 15:
// if this is a read command - ignore the rest
if (BS(PINB, PB2)) {
start = 0;
return;
}
break;
case 18:
// inject bit
if(bits & (1<<2)) {
H(DDRB, PB2);
H(PORTB, PB2);
} else
L(DDRB, PB2);
break;
case 20:
// inject bit
if(bits & (1<<1)) {
H(DDRB, PB2);
H(PORTB, PB2);
} else
L(DDRB, PB2);
break;
case 22:
// inject bit
if(bits & (1<<0)) {
H(DDRB, PB2);
H(PORTB, PB2);
} else
L(DDRB, PB2);
break;
case 24:
// injecting done
L(DDRB, PB2);
break;
// ignore write command to specifie
// address
case 27: // this bits should be set
case 29:
case 31:
case 39:
case 41:
case 43:
case 47:
case 49:
if (!BS(PINB, PB2))
start = 0;
break;
case 33: // this bit shuld be clear
case 37:
case 45:
case 51:
if (BS(PINB, PB2))
start = 0;
break;
case 54:
// we're here so we set WP to high
// disabling signle wrtie on this
// address
H(PORTB, PB0);
break;
case 72:
// disable WP, enable writes again
L(PORTB, PB0);
start = 0;
return;
default:
break;
}
++clk;
}
}
/****************************************************************************/
/* Main */
/****************************************************************************/
int main() {
// set SDA pin as input, later for a moment
// we'll need to set is as output and make a
// pullup on SDA line to set more significant
// bits in eeprom cell address
L(DDRB, PB2);
L(PORTB, PB2);
// set SDL pin as input (forever)
L(DDRB, PB1);
L(PORTB, PB1);
H(DDRB, PB0); // WP eeprom pin
L(PORTB, PB0);
L(DDRB, PB4); // bank choose button
L(PORTB, PB4);
// SDA interrupt is falling edge since
// it need to match START condition
H(MCUCR, ISC01);
L(MCUCR, ISC00);
// SCL pin change interrupt
H(PCMSK, PCINT1);
// turn on interrupts
H(GIMSK, INT0); // SDA
H(GIMSK, PCIE); // SCL
H(PRR, PRTIM1); // shut down unused modules
H(PRR, PRTIM0);
H(PRR, PRUSI);
H(PRR, PRADC);
// enable global interrupts
sei();
while(1) {
delay_ms(500);
if(!BS(PINB, PB4)) {
// when button is pressed, move to another bank
if(bits != MAX_BITS)
bits++;
else
bits = 0;
}
}
}
No comments:
Post a Comment