how would a hello world in 2wire USI be?

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello; i'm just new to this forum aswell as AVR programming. im come from the easy arduino world.

I've been more than a couple of months struggling to get the Attiny's hardware serial working. I have seen a lot of tutorials, reviewed libraries, and tried a lot of things, with no success at all (exept from a software driven serial, which is too slow for my need). I cannot guess what of all the possible mistakes i'm making; C programming for me, is a lot like magic; and surely i misunderstand a lot of terms.

I think that for any AVR freak would be piece of cake to write a code that just sends a single byte. I think that from there i'd be able to build this ideal communication method, and understand the logic.

I'm using AVR dude with C on ATtiny85, but also have winavr (no idea how winavr is used anyway)

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The USI is pants for implementing a UART.
If you want to TX and RX simultaneously like a real UART, you need to use INT and TIMER interrupts.

Life is a lot simpler with the correct chips. e.g. mega328P.
If you want a 'small' Tiny, look at the Tiny1634.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was actually thinking to make a bus, cheaply of two wires (Not I2C nor UART). I liked the idea of working at a very low level, to customize the communication protocol, but mostly im thinking to focus in that particular chip, to thenn be able to share knowledge with people in my makerspace. That's why i thought of attiny.

Today i tweaked my bitbanging protocol, and achieved a 1uS bit width. that passed my minimum freq treshold; but i'm sure that the hardware implementation of byte sending would be much better. I can't stand to have that whole technology unused in the IC. I currently send clock trough one line, and synched data trough the other.

The other thing is that i can barely program AVR. that is why i was asking for a bit of guidance, unless it's not a piece of cake as i'm supposing.

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The USI works fine for SPI and I2C.
Personally, I don't think it is acceptable to have to 'change direction' for an asynchronous UART protocol.

If you only want to TX, the USI is fine. For only TX, you can bit-bang it very easily.

I still reckon you should choose a different MCU.

If you want an accurate, jitter-free software UART, Google "danni (Peter Danegger) soft UART"

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First you need to learn to use the compiler with something more simple I guess.
If you want to use the tiny85 it's not a problem just some more work.
How fast does the tiny 85 run ? do you use internal or external clk ?
max TX speed for the USI is clk/2 (the code is in the datasheet written in ASM but a C compiler should generat close to same code).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

what i'm pretty lost with is the exact words. i hace tried several times to access the hardware USI thing with no success.
i made a software sender which is as follows:

int cc=wat;//CC is what is to be sent 
char pb=PORTB&(~((1<<PB0)|(1<<PB2)));
PINB&=~(0x00|(1<<PB0)|(1<<PB2));
nops(0xffff);
PORTB=pb|(((1<<PB0)&(0xff>>0))|((1<<PB2)&(0xff)));//1at bit is always 1 because is a flag
PORTB=pb|(((1<<PB0)&(0xff>>0))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(0xff>>0))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(0xff>>0))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(0xff>>0))|((1<<PB2)&(0x00)));

PORTB=pb|(((1<<PB0)&(cc>>0))|((1<<PB2)&(0xff)));//write a bit with clock on
PORTB=pb|(((1<<PB0)&(cc>>0))|((1<<PB2)&(0x00)));//thae same bit with clock off

PORTB=pb|(((1<<PB0)&(cc>>1))|((1<<PB2)&(0xff)));//....
PORTB=pb|(((1<<PB0)&(cc>>1))|((1<<PB2)&(0x00)));
PORTB=pb|(((1<<PB0)&(cc>>2))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>2))|((1<<PB2)&(0x00)));

PORTB=pb|(((1<<PB0)&(cc>>3))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>3))|((1<<PB2)&(0x00))); 
PORTB=pb|(((1<<PB0)&(cc>>4))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>4))|((1<<PB2)&(0x00)));

PORTB=pb|(((1<<PB0)&(cc>>5))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>5))|((1<<PB2)&(0x00)));
PORTB=pb|(((1<<PB0)&(cc>>6))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>6))|((1<<PB2)&(0x00)));



PORTB=pb|(((1<<PB0)&(cc>>7))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>7))|((1<<PB2)&(0x00)));   
PORTB=pb|(((1<<PB0)&(cc>>8))|((1<<PB2)&(0xff)));//write en shift register, avanzar
PORTB=pb|(((1<<PB0)&(cc>>8))|((1<<PB2)&(0x00)));//clok 0

PORTB=pb|(((1<<PB0)&(cc>>9))|((1<<PB2)&(0xff)));//....
PORTB=pb|(((1<<PB0)&(cc>>9))|((1<<PB2)&(0x00)));
PORTB=pb|(((1<<PB0)&(cc>>10))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>10))|((1<<PB2)&(0x00)));

PORTB=pb|(((1<<PB0)&(cc>>11))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>11))|((1<<PB2)&(0x00)));
PORTB=pb|(((1<<PB0)&(cc>>12))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>12))|((1<<PB2)&(0x00)));

PORTB=pb|(((1<<PB0)&(cc>>13))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>13))|((1<<PB2)&(0x00)));
PORTB=pb|(((1<<PB0)&(cc>>14))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>14))|((1<<PB2)&(0x00)));

PORTB=pb|(((1<<PB0)&(cc>>15))|((1<<PB2)&(0xff)));
PORTB=pb|(((1<<PB0)&(cc>>15))|((1<<PB2)&(0x00)));
//clock termina apagado


//lcuando el arduino recibe el bit, debería limpiar el bit 0, abriendo la linea.




PORTB&=~(0x00|(1<<PB0)|(1<<PB2));
PORTB|=(0x00|(1<<PB0)|(1<<PB2));

And works fine: it fully writes two bytes (-1 bit, for flag purposes) into a shift register with leds; using around 1uS (8clocks) per bit.

I was wondering if i could use a shift register inside the AtTiny exactly as i used the hard one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, before being more and more complicated, have you thought of ... making your code simpler (it can be a basis for a bit bang'ed sender, with adaptations).
Say :

PORTB=pb|(((1<<PB0)&(cc>>9))|((1<<PB2)&(0xff)));//....
PORTB=pb|(((1<<PB0)&(cc>>9))|((1<<PB2)&(0x00))); 

could be replaced by:

uint8_t k;
k=9;
PORTB=pb|(((1<<PB0)&(cc>>k))|((1<<PB2)&(0xff)));//....
PORTB=pb|(((1<<PB0)&(cc>>k))|((1<<PB2)&(0x00))); 
k=10;

Strangely enough, the next two lines will become the same... You might make a loop to send each and every byte of cc (and, with proper delays, it might become an asynchronous signal, with removing the part dedicated to clock -PB2, messeems-, necessary with synchronous transmission, but useless with async ... ).

Edite you obviously should read -and I should have written- "each and every BIT of cc" instead "of each and every byte"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Whether you are an I2C master or Slave, the USI is fairly simple and easy to use. It works well.

I can not believe that a human being would even attempt to write such statements. I certainly have no intention of reading it. You deserve a medal !!!

Seriously, any regular human brain can only absorb 'simple' algorithms. If you can reduce it to fit on a page, it might be possible to 'maintain'.

Hint. You replace the reams of in-line statements with macro(s). The PC will expand macros without typos or spelling mistakes !

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You try to access th k-th bit of cc (and cc gets distroyed);
k-th bit of cc can be tested this way :

for (uint16_tmask=1; mask != 0; mask = mask + mask) {// mask is doubled and is unsigned, 16 bits....
  if ((cc & mask ) == 0) { // kth bit is low : sends zero
     PORTB = pb|  //data
      ((1<<PB2)&(0xff)); // clock
     PORTB = pb|  //data
      ((1<<PB2)&(0x00)); // clock
  } else {   // sends  (data on Port0)
      PORTB = pb| (1<<PB0) | //data
                            ((1<<PB2)&(0xff))); // clock
     PORTB = pb|  (1<<PB0) | //data
                         ((1<<PB2)&(0x00))); // clock
  }
}//for

clock is raised while data may be updated... (for synchronous transfer, maybe one should wait a little that data change; maybe they bit k of data is validated at falling clock edge, then it seems OK)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay. i so got a cleaner code for two wire transfer, i write into the same shift register; to test whether it sends or not.
I actually can't even get the clock signal going in an oscilloscope. ¿what's wrong?

#include  
#include  
#include  

#define CTRL_PORT   DDRB 
#define DATA_PORT   PORTB 
#define PCK      PB2 //pindeclock
#define PCL      PB0 //pin de scl


unsigned char cData; 
unsigned int mm=0;

//USI master 
void init(void) 
{ 
   //Configure outputs 
   CTRL_PORT |= _BV(PCL) | _BV(PCK); 
   DDRB|=1<<PB0|1<<PB2;
} 

unsigned char Transmit(unsigned char data) 
{ 
   //Load data 
   USIDR = data; 
    
   //Clear the USI counter overflow flag 
   USISR |= _BV(USIOIF); 

   do 
   { 
   USICR = (1<<USIWM1) | (0<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC); 
   } while((USISR & _BV(USIOIF)) == 0); 
    
   return USIDR; 
} 




int main(void) 
{ 
	init(); 

	while(1){  
	   mm++;  
	   _delay_ms(30);
		PORTB=0X00;
	   cData=Transmit(mm); 
	} 
       
} 

This was copied from somewhere in internet, but i changed the USICR to work in two wire instead of three wire.
I expect that if i use the standard sending routine, will be also easier to recieve data then.