Sunday, July 10, 2016

Inject additional bits into I2C bus, Attiny45 C source code


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