SPI -> 74HC595 problem.

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

Hi all!

Im interfacing 74hc595 to my avr, im insufficient pins at moment :(
AVR used: (tiny 2313)
program used: codevisionavr

Im having problems at coding the code. no led working :D

Can anyone say if that schema is right??

i have now:

AVR 595
pin 19 sck/ucsk <---> pin11 sh_cp
pin 18 miso (??)
pin 17 mosi <---> pin14 data input
pin 16 pb4 <---> pin12 st_cp
vcc (+5v) -> pin10 reset

Can i please have some sample C code for taking 595 to work?
i have searched everyplace at internet, no luck. there is not much avr examples there.
also i tried to code some but no luck. i just dont know the commands about to take that working. no resources anyplace at internet about that info :(
i finded pic examples, but those will not work. heh.

Thanks already for all!

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

1. Why use SPI? , SPI regs have to be setup first correctly. SPI will load the HC595 but you may have to do some additional bit bangin (595 pin 12) to get it done depending on the result you are looking for . Either way I have found it is easy to bit bang in Codevision C or drop into ASM , you will have more control of the 595 than using SPI alone.
2. Assume HC595 pin 13 is logic 0 (enable output) since it was not listed in your schema.
3. If you enjoy experimenting then set up AVR port pins for output and try using Codevision Port bit manipulation and recreate the waveform and function table on a hc595 datasheet in code. Once you have that working, understand the hardware/software interaction and enjoy a small bit of success; adding functionality to the code should also be easy at that point.
4. There is code on the net for 595 connected to other micros like some 8 pin i/o starved projects (like PIC,Moto). Most of what I have seen is ASM but it can be translated to C easily.
5. While somewhat off topic one of the things I like about the new PIC Mplab is the logic analyzer wavform viewer and trace function..when bit bangin or watching micro pins like the SPI it makes it easy to verify code if you do not have a real logic analyser or scope.....I do not believe Atmel's AVR Studio has ths feature and (hoefully if they are listening) maybe someday Atmel will add this to AVR Studio.

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

riku2015 wrote:
Can i please have some sample C code for taking 595 to work?

Here's a "write" routine:

/*  
* WriteShiftReg:
*	Writes 1 byte of data to the shift register chain
*  	Author: John Lopez
*  	Parameters:
*		data: data to write
*  	Returns: none
*  	Warnings: 
*     This will write one byte into the shift register chain. 
*     If we are writing multiple bytes, the function will have   
*     to be called multiple times in the correct order in     
*     order to place the data in the proper locations. 
*     The shift register outputs will become tristated when 
*     this function is called and will remain tristated until   
*     ShiftRegEnable() is called.	
*     This function does NOT load the shift registers, see 
*     ShiftRegLoad.
*  See Also:
*		ShiftRegEnable, ShiftRegClear, ShiftRegLoad
*/
void WriteShiftReg(uint8_t data)
{
	uint8_t count;		/* loop counter */
	uint8_t reg;		/* data register */
	uint8_t clockval;  /* clock register */
	
	ShiftRegDisable();	/* Tristate outputs */
	
	/* cache current values */
	reg = PORTD;
	clockval = PORTC;
	
	/* Loop through data */
	/* We start at the LSB */
	for(count=0; count<=7; count++)
	{
		if((data & (1<<count)) )	/* If bit number "count" is a one... */
		{
			reg |= 0x80;			/* ...force the data line to a one */
			PORTD = reg;
			
			clockval &= 0xF7;		/* clock low */
			PORTC = clockval;		/* clock pulse out */
			clockval |= 0xF8;		/* clock high */
			PORTC = clockval;		/* clock pulse out */
		}
		else	/* ...Bit number "count" is a zero */
		{
			reg &= 0x7F;			/* data line forced to zero */
			PORTD = reg;

			clockval &= 0xF7;		/* clock low */
			PORTC = clockval;		/* clock pulse out */
			clockval |= 0xF8;		/* clock high */
			PORTC = clockval;		/* clock pulse out */
		}
	}
}

Some things to note:

This isn't using SPI, I'm just bitbanging the IO lines.
SRCLK above is PORT C bit 3.
SER above is PORT D bit 7.

This code is for a Mega16, so you may have to change the port & bit settings.
To be honest, I found some of the 595 datasheets to be very hard to understand. The TI datasheet (SN74HC595) is clearer than some others. I'd suggest finding this and studying the timing diagram until you understand how the thing works.

The Load, Clear, Enable functions mentioned in comments above are pretty much just wrappers for the various inputs to the 595. *Important*: you won't see the LED light even with this code until you load the shift register outputs (RCLK on TI datasheet) and enable the shift register outputs (OE on TI datasheet).

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

Thanks for answers!

john i did not make your code work :/ but anyway i have now something working.

i have it work now. but anyway it's not working how i want :(
i want leds stay on, example all leds light up. now it lights only one by one? huh?

Did i make something wrong?
i tried just like datasheet says, and that is not working. anyway is 595 should work that way???
i have code here:

void PORTTI_595(unsigned char send_data)
{   

// AVR              74HC595
// PIN 16 (P4)      PIN 14 (SER)
// PIN 15 (P3)      PIN 12 (RCLK)
// PIN 14 (P2)      PIN 11 (SRCLK)

int bit_mask;     

PORTB = 0x00; 

    

// for (bit_mask=0;  bit_mask<=8 ;bit_mask++) //<<=1
 for (bit_mask=1; bit_mask ;bit_mask <<=1) 
   { 
             
 
        for (i = 0; i < 40000; i++)  {  wait (); };
                if((send_data & bit_mask))
                        { PORTB |= 0x8; }
                else
                        { PORTB &= 0x7; }
     
             if( bit_mask < 1 )
                {       
                PORTB |= 0x10;
                }
         else 
                {
                PORTB &= 0x9; 
                }
  
   PORTB |= 0x04;
   for (i = 0; i < 40000; i++)  {  wait (); };
   PORTB &= 0x3;
   }
   
//PORTB |= 0x10;
//PORTB |= 0x04;
//PORTB &= 0x9;
//PORTB &= 0x3;  
//PORTB |= 0x04;  
//PORTB |= 0x04;
//PORTB &= 0x3;
//PORTB |= 0x10; for (i = 0; i < 40000; i++)  {  wait (); };
//PORTB &= 0x3;
//PORTB &= 0x9;  
  
}

already thanks for answers!

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

Quote:
AVR 595
pin 19 sck/ucsk <---> pin11 sh_cp
pin 18 miso (??)
pin 17 mosi <---> pin14 data input
pin 16 pb4 <---> pin12 st_cp
vcc (+5v) -> pin10 reset

First you have to store one byte into the storage register by using the SH_CP clockpin.
Then you give one clockpulse on the ST_CP, now the data is set on the output pins of the 595.
(Watch the timing of the pins, AVR's switch fast.)

8)

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

yes i have done it. i have waits(sleep) at the code, so i can wath the voltages at pins.
it only shows last led, not all if i code all to get on.

i use 74HC595N philips shift register

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

I paste my testcode here.
So people can see im really trying to make this work.
I taked this almost from pdf of 595
correct if im making something wrong.

CODE



while (1)
      {


 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x10;  // DS/Ser UP
 PORTB |= 0x14;  // DS/ser AND CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 PORTB &= 0x9; // DS/ser DOWN

 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP! 
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN! 
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!

 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN

 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!
 
 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 
 PORTB |= 0x10;  // DS/Ser UP
 PORTB |= 0x14;  // DS/ser AND CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 PORTB &= 0x9; // DS/ser DOWN
 
 PORTB |= 0x8; // PIN 11 (SRCLK/ST_CP)  UP!
 PORTB &= 0x7;  // PIN 11 (SRCLK/ST_CP)  DOWN!

 PORTB |= 0x04;  // CLOCK UP
 PORTB &= 0x3;  // CLOCK DOWN
 

for (i = 0; i < 800000; i++)  {  wait (); };
      };
}

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

Quote:

PORTB |= 0x10; // DS/Ser UP
PORTB |= 0x14; // DS/ser AND CLOCK UP
PORTB &= 0x3; // CLOCK DOWN
PORTB &= 0x9; // DS/ser DOWN

You will need to work on your logic operations.

PORTB &= 0x3; // CLOCK DOWN

sets all but PB0 & PB1 low (including DS/SER PB4).

To set a bit (let's use bit 3): PORTB |= 0x08; or PORTB |= (1 << 3);
To clear a bit: PORTB &= ~0x08; or PORTB &= ~(1 << 3);

Here are pieces from my app that has a 74165 and 74595 on the same lines, and has 9 outputs on the '595:

// Latches, Chip Selects, Enables
	// Load 74HC165 on falling edge of this signal
#define	SPI_LOAD			PORTD.6
	// Transfer to outputs of 74HC595 on rising edge of this signal
#define	SPI_XFER			PORTB.6
	// Soft SPI output line to 74HC595
#define	SPI_MOSI			PORTB.5
	// Soft SPI input line from 74HC165
#define	SPI_MISO			PIND.7
	// Soft SPI clock line to/from 74HC165 & 74HC595
#define	SPI_SCK				PORTB.7
	// Clock in 8 '165 bits plus the '165 SDI pin value
#define	SPI_INPUTS			9
	// Clock out 8 '595 bits, then leave SPI_MOSI in the state of the 9th bit
#define	SPI_OUTPUTS			8

...
//
// **************************************************************************
// *
// *		C O N F I G _ L E D S
// *
// **************************************************************************
//
//	A bank of nine red/green indicator LEDs are connected to the system inputs.
//
//	A 74HC595 serial-to-parallel chip controls the state of eight of them;
//	the ninth is controlled by the state of the system SDI (AVR MOSI) line
//	when the operation is completed.
//
// 74HC595 sets indicator "direction"  (red/green for NC/NO)
//
//
void						config_leds			(unsigned int indicators)
{
unsigned int 		work;				// working value of indicators
unsigned char 		looper;				// loop counter

	work = indicators;					// try for register operations


	SPI_SCK = 0;						//	drive the clock low.
	SPI_XFER = 0;						//	drive the latch low.


  	for (looper = 0; looper < SPI_OUTPUTS; looper++)
  		{
		SPI_MOSI = (work & 256) ? 1 : 0;// present the bit to the data line
		SPI_SCK = 1;					// raise the clock to present the bit to the line
		work <<= 1;						// prepare next bit & take some time
		SPI_SCK = 0;					// drop the clock for the next go-round
  		}

	SPI_XFER = 1;						// drive the latch RCLK/XFER high, latching data.
	SPI_MOSI = (work & 256) ? 1 : 0;	// present the 9th bit to the data line; take time
	SPI_XFER = 0;						//	drive the latch low.

}

You will need to adjust the bit operations to handle the port-wide logic as I showed above, since your free compiler doesn't let you use the convenient "PORTB.5" etc. syntax that my pay-for CodeVision compiler does.

[Note to EW: Round 47 of Compiler Wars.]

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

many thanks for the example.

argh.
the for loop have some problems. it runs only 1 time. i dont find any problem yet.
i take more look tomorow :D

i go now sleep :) here is morning almoust in finland :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
//**************************************
//	SPI_Test  Mega8 mit 8 MHz
//	SPI mit 4Mhz
//	Mega8   > HC595
//	Mosi    > Serial in
//	Sck     > Clock
//	PB2/SS  > RCK+G
//**************************************

//**************************************
//            I N C L U D E
//**************************************

#include     
#include     // Register Definitionen fuer Mega8 
#include 
#include 
#include 

//**************************************
//   G L O B A L   V A R I A B L E
//**************************************

volatile display_mem[16]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
							0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,
				};		// 10 Positionen
volatile unsigned int pos;

//**************************************
//            M A I N
//**************************************

void main(void)
{

PORTB = 0xFF;
DDRB = 0xFF;		// SCK/MOSI/SS als Ausgang / (0xFF)Alle Ausgang

//SPI
SPCR = 0x50;
SPSR = 0x01;		// SPI/MSTR/SPIX2

PORTD = 0x00;		
DDRD = 0xff;		// PortD Ausagang

//Timer0
TCCR0 = 0x05;		// Timer0 / 1024
TIMSK = 0x01;

pos=0;
sei();
for( ;; );
}

SIGNAL(SIG_OVERFLOW0)
{
static unsigned char Tick;
 Tick++;
 if (Tick > 31)
   {
	SPDR = display_mem [pos];		// Daten per SPI senden
    while (!(SPSR & (1<<SPIF)));	// Warten bis Übertragung beendet
	PORTB = 0xFF;					// HC595 > Shift in Storage / G disable
	PORTB = 0x00;					// HC595 > G enable
	
	PORTD =(~pos);					// PortD invertiertes pos ausgeben
	Tick = 0;						// da STK500 log.0 LEDs an
	pos++;
   if(pos>15)						// nach Datenbyte 16 
   {
   pos=0;							// wieder von vorn
   }
  }
TCNT0 = 0x04; 						// Timer0 neustart
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi theush!

can you please explain me one thing. how this can work with wrong pin assigment?

look my code (on the code have pinouts connections)
i take look to 595 datasheet and there is saying DS should trig those? or im wrong? Im not understanding how this can work.

anyway that is working.. but i need explain how?
not work like im understanding 595 datasheet!?

im confused.
im understanding:
SPI_XFER should be SER pin 14 on 595
SPI_MOSI should be RCLK pin 12 on 595
SPI_SCK it's a clock at pin 11 on 595..

so, SER and RCLK is opposet ? explain please.


// Latches, Chip Selects, Enables
   // Load 74HC165 on falling edge of this signal
//#define   SPI_LOAD         PORTD.6
   // Transfer to outputs of 74HC595 on rising edge of this signal
#define SPI_XFER PORTB.3
   // Soft SPI output line to 74HC595
#define SPI_MOSI PORTB.4
   // Soft SPI input line from 74HC165
//#define   SPI_MISO         PIND.3
   // Soft SPI clock line to/from 74HC165 & 74HC595
#define SPI_SCK PORTB.2
   // Clock in 8 '165 bits plus the '165 SDI pin value
//#define   SPI_INPUTS         9
   // Clock out 8 '595 bits, then leave SPI_MOSI in the state of the 9th bit
#define SPI_OUTPUTS 9 

//MY CONNECTION!!!
// AVR              74HC595
// PIN 16 (P4)      PIN 14 (SER/latchi?)
// PIN 15 (P3)      PIN 12 (RCLK/Data)
// PIN 14 (P2)      PIN 11 (SRCLK/kello) 
                      
long int i;


void config_leds(unsigned int indicators)
{
unsigned int work;            // working value of indicators
unsigned char looper;            // loop counter

   work = indicators;               // try for register operations 
   
   SPI_SCK = 0;                  //   drive the clock low.
   SPI_XFER = 0;                  //   drive the latch low.
                           
     for (looper = 0; looper < SPI_OUTPUTS; looper++)
        {
      SPI_MOSI = (work & 256) ? 1 : 0;  // present the bit to the data line
      
      SPI_SCK = 1;                    // raise the clock to present the bit to the line  
      work <<= 1;                       // prepare next bit & take some time
      SPI_SCK = 0;                      // drop the clock for the next go-round  
        }                                  
        
SPI_XFER = 1;                  // drive the latch RCLK/XFER high, latching data. 
SPI_MOSI = (work & 256) ? 1 : 0;   // present the 9th bit to the data line; take time    
SPI_XFER = 0;                  //   drive the latch low.

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

My 74HC595 symbol shows CLK on pin 11, which goes to my soft SPI_SCK. Pin 12 shows XFR, which goes to my soft SPI_XFER. Pin 14 is shown as SER/SDI, which goes to my soft SPI_MOSI.

I don't know if different brands and different datasheets for the '595 label the signals differently. Pin 14 is the data; pin 12 is the latch; pin 11 is the clock.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

how about connecting 2x 74HC595 ?

i just incrase SPI_OUTPUTS from 9 to 17?

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

Quote:

i just incrase SPI_OUTPUTS from 9 to 17?

Yes, that is true. Perhaps you should get one working first?

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Oh, lets complicate it!!! That just makes it more challenging for you Lee. Don't you want a sliding scale challenge?

But if you could teach some of these guys to run really fast, think of how much easier it would be for you to teach them how to crawl!!!

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

heh, i have already one working.

that is becouse i want try 2 next :)

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

Quote:
heh, i have already one working.

that is becouse i want try 2 next

Thanks for letting us know. Now you know enough to get three or four 74xx595 cascaded devices working on your own, right?

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

I had 8 of em in a chain for chip selects for a bunch of displays. I had to put a one of 64 code into em.

Imagecraft compiler user

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

got it working :)

now it has 65536 (16bit) options :DD

Thanks for any help for all who helped me!

-Riku

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

Hi
I have the same problem with at90s2313 and 74HC595.
Will you send me source code for CodeVision AVR.

Thanks :D

Thanks for your help.
Roki

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

JUst a note of interest:

I have done this method output expansion in the past, as I assume many experiences people have. My method goes one step further by automatically enabling the outputs of the latch at the hardware level. How?

assuming the latch has a positive edge clock input and an active low output enable, then i generate the /OE signal from the clock using a resistor, diode and cap. the uC holds the clock low when not using it to load data into the S/R. the resistor/cap combination form an integrator that goes low after a few ms auto matically enabling the outputs. once the cock goes high the capacitor charges up through the diode connected in parallel with the resistor, disabling the outputs immediately.

This method is valuable when only 2 I/O pins are available.

DFR

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

Quote:

... once the cock goes high ...

Cover your eyes, Gwen.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.