I2C sniffer

I2c sniffer can be implemented entirely in software , but it is much more convenient to USI . Mainly because USI has built- Start condition detector, and even with a separate interrupt.
That’s the only problem is that the self – USI in itself a useless piece of the state machine , and the logic necessary to implement the software . On the one hand, it is not convenient, and on the other – it is possible to stir , for example, sniffer , which is the usual TWI can be done.

By the logic of the protocol i2c communication , the transmission byte goes in two directions. If we pass the bytes, the need to transfer 8 bits of “there” , and read one bit “out there .” If we read that on the contrary .
In the case of same – sniffer , there is no “there” and “there” . There is only one direction – ” past .” It is somewhat easier task. We need only to listen to the line and put the data into the buffer. From this buffer, they are transferred to the computer .

All dvizhuha line is divided into four types:
0x1 – Start detekted
0x2 – Stop detekted
0x4 – + ACK Byte
0xC – Byte + NACK

For each event entry is 4 bytes . First (Senior ) bytes – this is the event code (those most – 0x1, 0x2 …). In the second data . For the first two events data is not needed, then the second byte = 0. The last two bytes – the value of the timer. It starts as soon as the first to be caught start-condition, and is reset by a command from the computer. Period of one ” tick ” timer – 1ms . It can be considered a little more than a minute , more than enough to capture any repeats and other unknown things that are happening on the line sometimes .

If we decided to catch the Start condition in software, then , would have had to start on the leg of SDA interrupt , and there is already starting to define it , or just switched SDA . And with USI such problem is simple: include interruption of USI START and wait …

Here is the interrupt handler :
procedure USI_Start; org 0xF;
 asm / / Clear the flag and counter = 15.
 in r16, USISR
 andi r16,% 11110000
 ori r16,% 10001111
 out USISR, r16
 USI_recv_state: = 2 ;

 / / Timer is started up
 if TCCR0B = 0 then
   Timer: = 0 ;
   TCNT0: = 0 ;
   PSR10_bit: = 1 ;
   TCCR0B: = 4 / / prescaler 256
 / / Pushes the data to the clipboard
 push_to_buffer (f_start, 0);

The first thing we reset the flag USISIF. This must be done as quickly as possible , for as long as the flag is raised , USI will clamp the line SCL. We then pushed into counter USICNT 0x0F, and write to a variable USI_recv_state 2 . This is a preparation for the reception of data ( I know, now looks like black magic , but then it becomes more clear ) . Check if the timer is not running , then reset it and run.

To Identify the stop-condition we have provided almost the same as that for a start. Only interrupts greedy . Therefore it was necessary to add to the cycle of the program checks the flag USIPF.

   if USIPF_bit = 1 then
     USIPF_bit: = 1 ;
     push_to_buffer (f_stop, 0);

Here, I think , do not have anything new . Reset flag (for this you need to burn it edinichku ) and stuffed into a message buffer that caught the stop .

The most interesting – catch data . As many as 9 bits . USI we have configured :
USICS1 = 1 ; USICS0 = 0 ; USICLK = 0 – this means that for every positive edge on the SCL, the data register USIDR will shift , and it will be recorded with a bit line SDA. A counter USICNT is ticking on each edge of SCL.