SPI on m64

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

hello,

i'm trying to get a simple SPI code working, and when i measure the SCK pin (PB1) with the oscilloscope i get a frequency of 15MHz, with a Vp-p of ~68mV... I would expect a freq of 7.3728MHz/64=115.2kHz at that pin. What am i missing?

Thank you!
- Eric

#define F_CPU 7372800UL						

#include 
#include 
#include 
#include 		
#include 
#include 
#include 
#include 
#include 					
#include 

/*SPI configuration*/ 
#define DD_SS   DDB0 
#define DD_SCK	DDB1
#define DD_MOSI	DDB2
#define DD_MISO	DDB3 
#define DDR_SPI	DDRB 

#define SPI_PORT PORTB

void SPI_MasterInit(void)
{
	//Set MOSI, SCK, CS output, all others input
	DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);	
	// Enable SPI, Master, set clock rate fck/64 --> 115.2kHz
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1);				
}

void SPI_MasterTx(char cData)
{
	// Start transmission
	SPDR = cData;		
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));				
}


int main(void) 
{
SPI_MasterInit();

	while(1) 
	{ 
		// Activate the CS pin - LOW
		SPI_PORT &= ~(1<<DD_SS);
		
		SPI_MasterTx('A');
		
		// Deactivate CS pin - HIGH
		SPI_PORT |= (1<<DD_SS);	
	
		_delay_ms(3000);
	}
}

EDIT - there is no slave connected at the moment. it's just the atmega64

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

Do you have pull-ups on the lines? If not what you are seeing is probably a reflection of the system clock. Also to see the clock you have to send something, SPI clock is active only when transmitting, and idle state depends on clock polarity configured. In most cases it's idle high impedence with pull-ups, and active low.

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

hugoboss wrote:
Do you have pull-ups on the lines? If not what you are seeing is probably a reflection of the system clock. Also to see the clock you have to send something, SPI clock is active only when transmitting, and idle state depends on clock polarity configured. In most cases it's idle high impedence with pull-ups, and active low.
Bad grass. Change your dealer :D:D:D

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

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

Orlly? How so?

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

Sorry, I have no idea of how to change the grass dealer :D:D:D

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

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

thank you hugoboss, "SPI clock is active only when transmitting" - that was what i was missing... the clk is working just fine, I'm still not being able to communicate to a DAC chip TLC5628CN http://focus.ti.com/lit/ds/symlink/tlc5628.pdf
According to the datasheet, i need to send a data packet by following this sequence:
LDAC (CS)-> LOW
LOAD -> HIGH
A2 A1 A0 RNG D7 D6 D5 D4 D3 D2 D1 D0
LOAD -> LOW
LDAC -> HIGH (or keep it low...)
i've attempted different things but when i measure the voltage at the pin i'd want to see the analog voltage, the chip is still not responding. For ex, a data packet i tried is
A2 A1 A0 RNG D7 D6 D5 D4 D3 D2 D1 D0
0 1 0 0 1 0 1 0 1 1 1 1
where 10101111 = 175 in dec and i'd expect a voltage at DACC pin 16 of Vout = 5 * 175/256 = 3.4V

My code is shown below - and thank you for any input!

void SPI_MasterInit(void)
{
	DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);	
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);			
	SPSR = (1<<SPI2X);				
/*	SPI2X:1 SPR1:0 SPR0:1 --> SCK Frequency: fosc/8
	Recommended operating condition SCK ~1MHz
	7.3728MHz/8=0.9216MHz	*/
}

void dac_buffer(void)
{
	int k, data;
	char data_str[8];
	
	for (k=0; k<12; k++)			// clear tx_API[]
	{	SPI_dac[k] = 0;	}

	SPI_dac[0] = 0x00;	// A2
	SPI_dac[1] = 0x01;	// A1
	SPI_dac[2] = 0x00;	// A0
	SPI_dac[3] = 0x00;	// RNG Output 0-5V
	
	data = 175;
	itoa(data, data_str,2);//base2, binary??	
	//itoa(data, data_str,10);

	for (k=4; k<12; k++)
	{
		SPI_dac[k] = data_str[k-4]; 
	}

	/*SPI_dac[4] = 1;		// D7
	SPI_dac[5] = 0;		// D6
	SPI_dac[6] = 1;		// D5	
	SPI_dac[7] = 0;		// D4
	SPI_dac[8] = 1;		// D3
	SPI_dac[9] = 1;		// D2
	SPI_dac[10] = 1;	// D1
	SPI_dac[11] = 1;	// D0*/

	for (k=0; k<12; k++)
	{	SPI_MasterTx(SPI_dac[k]);	}
}

int main(void) 
{
	SPI_MasterInit();
		
	while(1) 
	{ 
		SPI_PORT &= ~(1<<PB0);	// LDAC LOW
		SPI_PORT = (1<<PB4);	// LOAD HIGH
		dac_buffer();
		
		SPI_PORT = (0<<PB4);	// LOAD LOW
		SPI_PORT |= (1<<PB0);	// LDAC HIGH - CS
		_delay_ms(1000);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

They're surely bits not bytes?!? The issue you may face is that there seem to be 12 of them, not 8 (the SPI transfer size). You might get this to work with 2 byte transfers and hope that the last 4 bits are ignored. Otherwise just bit-bang it.

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

right, bits! ok, so i modified the code to

void dac_buffer(void)
{
	char data1, data2;

	data1 = 0b01000011;
	data2 = 0b01010000;

	SPI_MasterTx(data1);
	SPI_MasterTx(data2);
}

but it's still not working. Is there any way to not send the last four bits? maybe counting the number of clock cycles and stop transmitting after sending 12bits? if not, i'll give bit-banging a try.
thank you!
- Eric

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

Quote:

if not, i'll give bit-banging a try

Sounds like a plan. After all SPI ain't exactly rocket science ;-)

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

i'm confused with using bit banging at the recommended clk frequency for this chip ~1MHz. Should i be using a timer? i was thinking of maybe something like this...

//data1 = 0b01000011;
//data2 = 0b01010000;
ISR(TIMER1_OVF_vect)
{	
	counter++;

	if (counter==1)
	{
		PORTB = 0b00000000;// bit11
	}
	else if (counter==2)
	{
		PORTB = 0b00000100;// bit 10
	}
	else if (counter==3)
	{
		PORTB = 0b00000000;// bit 9
	}
	... etc. 
							// bit 0
}

but there has to be a better way, and not even sure about how to set up the timer
TCCR1B = (1<<CS11);// CLK/8 prescaler
TIMSK = (1<<TOIE1);// Interrupts - Overflow timer1
if i understood it right, this would correspond to 7373800/8=921600Hz. So each cycle will have T=1us. and 65536 x 1us = ~65.5ms --> the timer will overflow every 65.5ms. Even with no prescaler, the timer would overflow every 8.89ms -> 112.5Hz... not good. So i guess timers is not the way to do it... or i'm just way confused... can i use a timer to overflow at a frequency of clock/8 ~ 1MHz

or is it possible to bit bang the MOSI pin and still use the SCK pin (SPI clock) at ~1MHz?

Thanks for any help

- Eric

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

The link to the DAC datasheet times out. Is the register you try to write to 12 or 16 bit in the DAC ? Are you sure your SPI connects between the 2 chips is correct ?

SPI_PORT = (1<<PB4);   // LOAD HIGH 

None of your posts sets this pin as an output.

This is the correct code to set it HIGH, and your set_it_low code for that pin's wrong too.

SPI_PORT |= (1<<PB4);   // LOAD HIGH 

Edit: Link's working now and SPI idles low and samples on clk falling. This is MODE_1 and you're at MODE_0.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Wed. May 11, 2011 - 07:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

at the recommended clk frequency for this chip ~1MHz

I think you'll find that is the maximum possible clock speed - not the speed you HAVE to drive it at. The great thing about synchronous serial links is that you can go just as fast as you choose to toggle the clock.

Using a timer seems like an awful lot of hassle. Why not just a nice tight for() loop where you take CLK high, output the next of the 12 data bits, then take CLK low (it reads on the falling edge the datasheet said) and repeat 12 times.

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

@indianajones11 - i was hoping that would fix the problem but still no luck. I'm pretty sure the connections are correct:
PB4 -> LOAD
PB0 -> LDAC
MOSI PB2 -> DATA
MISO - not used. pulled high
SCK PB1 - CLK

I don't think the datasheet mentions the size of the register. It's mouser part# TLC5628CN http://www.mouser.com/ProductDetail/Texas-Instruments/TLC5628CN/?qs=sGAEpiMZZMswix2y39yldQwNB6bjwIz%252b/SsmzlU1pO8%3d

@Cliff,

Quote:
The great thing about synchronous serial links is that you can go just as fast as you choose to toggle the clock.
Good to know that, i'll go with the for loop recommendation and report back.

Thanks again!

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

Using the SPI hardware and 2 byte transfer is fine for that DAC. Would you show your modified SPI hardware code after using my corrections ?

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

yes, sure, with this code i would expect ~2V at the DACH pin

#define F_CPU 7372800UL						

#include 
#include 
#include 
#include 		
#include 
#include 
#include 
#include 
#include 					
#include 

/*SPI configuration*/ 
#define DDR_SPI	DDRB 
#define SPI_PORT PORTB

void SPI_MasterInit(void)
{
	//Set PB4,MOSI, SCK, CS output, all others input
	//DDR_SPI = (1<<PB4)|(1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);	
	DDR_SPI = 0b00010111;
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);			
	SPSR = (1<<SPI2X);				
/*	SPI2X:1 SPR1:0 SPR0:1 --> SCK Frequency: fosc/8
	Recommended operating condition SCK ~1MHz
	7.3728MHz/8=0.9216MHz	*/
}

void SPI_MasterTx(char cData)
{
	SPDR = cData;	// Start transmission
	while(!(SPSR & (1<<SPIF)));// Wait for transmission complete
}

void dac_buffer(void)
{
	char data1, data2;

	data1 = 0b11100110;
	data2 = 0b01100000;

	SPI_MasterTx(data1);
	SPI_MasterTx(data2);
}

int main(void) 
{
	SPI_MasterInit();
		
	while(1) 
	{ 
		SPI_PORT &= ~(1<<PB0);	// LDAC LOW
		SPI_PORT |= (1<<PB4);	// LOAD HIGH
	
		dac_buffer();
		
		SPI_PORT &= ~(1<<PB4);	// LOAD LOW
		SPI_PORT |= (1<<PB0);	// LDAC HIGH - CS
		_delay_ms(1000);
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);

This is still mode 0.

SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)| (1<<CPHA);

Is what you need, mode 1.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

@indianajones11

Quote:
Edit: Link's working now and SPI idles low and samples on clk falling. This is MODE_1 and you're at MODE_0.

so Bit 2 – CPHA should be set to 1

SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPHA)|(1<<SPR0);	

still no analog output :/

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

yes, i just read your EDIT comment a few posts ago... still no analog output. i think i need a break :P

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

Seems to me like it's XXXX_A2_A1_A0_RNG D7_D0, try it in that format. AS I study fig 1 - fig. 4 it just makes my head HURT ( esp. fig 3/4...WTH TI )!!! Dude if that doesn't work, I'd just call TI and find out WTF up with their stank timing diagrams.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

just an update - (not sure what the XXXX_A2... format is..) i just called TI and well, i'll need to send a detailed email to their eng team to figure this out... Assuming the chip can only receive 12bits (and not 16) i tried bit banging as Cliff suggested, and i do get at least some response from the chip (with SPI i'd get nothing). When i send a 125 for instance (5V * 125/256) and i'd expect to get 2.5V, i get1.9V
200 - expecting 3.9V - get 2.98V
50 - expecting 0.97V - get 0.745V... so it's somewhat working...

The bit banging code is shown below (first time doing this so the inaccuracy could very well be due to some error in my code...)

#define F_CPU 7372800UL						

#include 
#include 
#include 
#include 
#include 
#include 
#include 					

void send_12bit_serial_data(void)
{
	int i;
	char data1, data2;

	data1 = 0b11000011;	// DACG, RNG 0
	data2 = 0b00100000;
   
// CLK high, output the next of the 12 data bits, then take CLK low 
	for (i=0; i<8; i++)		// send bits 11..4
	{
		PORTB |= (1<<PB1);// CLK HIGH

// consider leftmost bit
// set line high if bit is 1, low if bit is 0
	   
		if (data1 & 0x80) // 0b10000000
		{	PORTB |= (1<<PB2); }
		else
		{	PORTB &= ~(1<<PB2);}
 
// pulse clock to indicate that bit value should be read
		PORTB &= ~(1<<PB1);	// CLK LOW
	
// shift byte left so next bit will be leftmost
 		data1 <<= 1;	
   }

   for (i=0; i<4; i++)	// send bits 3..0
   {
		PORTB |= (1<<PB1);// CLK HIGH

		if (data2 & 0x80)
		{	PORTB |= (1<<PB2); }// MOSI pin
		else
		{	PORTB &= ~(1<<PB2);}
 
		PORTB &= ~(1<<PB1);// CLK LOW
		
		data2 <<= 1;
   }
}

int main(void) 
{
//PB1-SCK, PB0-LDAC, PB2-MOSI, PB3-MISO, PB4-LOAD	
	DDRB = 0b00010111;	//Set PB4,MOSI, SCK, CS output, all others input

	while(1) 
	{ 
		PORTB &= ~(1<<PB0);	// LDAC LOW
		PORTB |= (1<<PB4);	// LOAD HIGH

		send_12bit_serial_data();
		
		PORTB &= ~(1<<PB4);	// LOAD LOW
		PORTB |= (1<<PB0);	// LDAC HIGH - CS
		_delay_ms(1000);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your results suggest the reference is 3.8V not 5.0V.

3.8 * 125/256 = 1.9V
3.8 * 200/256 = 2.97V
3.8 * 50/256 = 0.74V

Presumably you'll find that

3.8 * 255/256 ~= 3.8V

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

!!!!!!!!! with 255 i get 3.797V...!!

how can that be if the reference voltage (VCC, REF1, REF2 pins) are all at 5V!? pretty confusing...

there's this RNG bit that when set to 1, it should give twice the voltage, that's still not working. but i'll take it to TI from here.

Thank you very much Cliff and indianajones11! btw, Cliff, i'm curious, 40873 posts!!! are you aiming 50k before you retire, or maybe 100k!? :)

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

Quote:

Cliff, i'm curious, 40873 posts!!! are you aiming 50k before you retire, or maybe 100k!? :)

By my calculations it could be about 157,000 :-)

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

Good job of bit-bangin' ! Vref from the datasheet is Vcc - 1.5V. The format meant that the 'X''s were don't cares in a 16 bit send. Fig. 3 and Fig. 4 make no sense with the clk, but your troubles are all behind you ! :)

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Quote:

Vref from the datasheet is Vcc - 1.5V

If Vref is 3.8V this means Vcc is 5.3V not 5.0V ?

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

nope, Vcc is 4.97V (output of a 7805 volt regulator)

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

Is Vref2 => DAC G connected to Vcc ?

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

yes, both Vref1, Vref2 (pins 11 & 14) are connected to Vdd 5V (pin 6) --- both Gnds and Vcc of m64 and chip connected together as well ---

i know it bothers that Vcc - Vref is not exactly 1.5V but it's working fine if knowing that Vref is 3.8V.. i'll get this clarified with TI and post any clarifications here.

Thank you again guys!

- Eric