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