SPI Atmega8a-pu i AD9833

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
adi19887
-
Posty: 52
Rejestracja: 22 mar 2010, 23:48
Lokalizacja: Poznań

SPI Atmega8a-pu i AD9833

Post autor: adi19887 » 18 paź 2013, 13:45

Witam serdecznie,

Chciałbym prosić osoby działające na forum o sprawdzenie kodu i toku myślenia (komunikacja SPI z DDS AD9833). uC nie generuje sygnału SCK - w ogóle nic :) być może się pomyliłem. Wykorzystane piny w atmedze widać w dziale kodu ze stałymi.

Kod: Zaznacz cały

//Stałe
#define F_CPU			16000000UL
#define SPI_DDR			DDRB
#define SPI_MOSI_BIT	PB3
#define SPI_SCK_BIT		PB5
#define SPI_CS_BIT		PB1
#define SPI_SPR			(1<<SPR1)
#define AD_FSELECT		11
#define AD_FREQ0		(1<<14)
#define AD_FREQ1		(1<<15)
#define AD_B28			13
#define	AD_FSYNC_DDR	DDRB
#define AD_FSYNC_BIT	PB1
#define	AD_SLEEP1		7
#define	AD_SLEEP12		6
#define AD_RESET		8

#define AD_F_MCLK 25000000 
#define AD_2POW28 268435456 
 
 
#define AD_FREQ_CALC(freq) (uint32_t)(((double)AD_2POW28/(double)AD_F_MCLK*freq)*4)
/***************/

#include <avr/io.h>
#include <util/delay.h>



typedef struct {
       float    freq[2]; 
       float    phase[2];
       float    mod_freq;
       uint8_t  freq_out;
       uint8_t  phase_out;
       uint8_t  mode; //sinus
       uint16_t command_reg;
   } ad9833_opcje_t;
   
ad9833_opcje_t ad9833_opcje;

void AD_FSYNC_LO();
void AD_FSYNC_HI();
void spi_init();
void spi_send_byte(uint8_t data);

//funkcja odpowiedzialna za wysylanie weartosci 16-bitowej
static inline void ad9833_send(uint16_t packet){
       spi_send_byte((uint8_t)(packet>>8));
       spi_send_byte((uint8_t)packet);
  }
  /***********************************/
//pozostale

/*************************************************/
void    ad9833_set_freq_out(uint8_t freq_out){
       ad9833_opcje.freq_out = freq_out;
       switch (freq_out){
           case 0:
               ad9833_opcje.command_reg &= ~(1<<AD_FSELECT); //Ad_fselect = 11 zeruje ten bit w rejestrze
               break;
           case 1:
               ad9833_opcje.command_reg |= (1<<AD_FSELECT); //Wstawia 1 do bitu
               break;
           case 2:
               //TODO
               break;
       }
  
       AD_FSYNC_LO();
       
       ad9833_send(ad9833_opcje.command_reg);
       
       AD_FSYNC_HI();
   }
   
void ad9833_set_frequency(double freq){
       uint32_t freq_reg;
       freq_reg = AD_FREQ_CALC(freq);
       ad9833_opcje.freq[AD_FREQ0] = freq; //Zapisuje czestotliwosc do struktury
  
       AD_FSYNC_LO();
       
       ad9833_send((1<<AD_B28) | ad9833_opcje.command_reg);	//jezeli command_reg jest 1 to wybierany jest FREQ1
       ad9833_send(AD_FREQ0 | (0x3FFF&(uint16_t)(freq_reg>>2 )));
       ad9833_send(AD_FREQ0 | (0x3FFF&(uint16_t)(freq_reg>>16)));
       
       AD_FSYNC_HI();
   }


//funkcja glowna
void ad9833_init(void){
        //init FSYNC pin (aka Chip select)
        ad9833_opcje.command_reg |= (1<<AD_B28);
        AD_FSYNC_DDR |= (1<<AD_FSYNC_BIT);
        AD_FSYNC_HI();        
        //some datasheet-proscribed delay here
        _delay_us(10);
        //start as half-asleep
        AD_FSYNC_LO();
        ad9833_send((1<<AD_SLEEP12)|(1<<AD_RESET)); //bit 6 = 1 to DAC bez mocy; Reset = 1 zeruje wewnetrzne rejestry.
        ad9833_opcje.command_reg |= (1<<AD_SLEEP12); //przepisuje wartosc do struktury
        AD_FSYNC_HI();
        //set some nice default values
        ad9833_set_frequency(0);
        ad9833_set_freq_out(0);
    
    }
/*************************************/



int main(void)
{
	spi_init();
	ad9833_init();
	ad9833_set_freq_out(0);
	ad9833_set_frequency(5000);
    while(1)
    {
		
        
	
    }
}

/****/

void spi_init(){
        SPI_DDR |= (1<<SPI_MOSI_BIT)|(1<<SPI_SCK_BIT)|(1<<SPI_CS_BIT);
    
        SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    }
    
void spi_send_byte(uint8_t data){
        SPDR = data;
        while(!(SPSR & (1<<SPIF)));
    }
    

	
void AD_FSYNC_LO()
	{
		
		PORTB &=~(1<<PB1);
		_delay_us(5);	//dobre wyrażenie
	}
	
void AD_FSYNC_HI()
	{
		_delay_us(5);
		PORTB |=(1<<PB1);	
	}
Dodatkowo załączam schematy układu fizycznego. Połączenia między nimi lutowane i sprawdzane multimetrem.
Załączniki
1.png
1.png (9.81 KiB) Przejrzano 5533 razy
2.png
2.png (14.03 KiB) Przejrzano 5533 razy

adi19887
-
Posty: 52
Rejestracja: 22 mar 2010, 23:48
Lokalizacja: Poznań

Post autor: adi19887 » 18 paź 2013, 19:04

To może inaczej bo zrobiłem krótszy kod by sprawdzić czy coś się dzieje. Najpierw na procka wrzuciłem migające diody (zeby sprawdzic czy zyje). Potem ten kod:

Kod: Zaznacz cały

//częstotliwość zegara
#define F_CPU 16000000UL 
#define BIT_MOSI	PB3
#define BIT_CS		PB1
#define BIT_SCK		PB5

#include <avr/io.h>
#include <util/delay.h>

/**************************Ciala funkcji*********************************/
void spi_init()
{
	/* Set MOSI, SCK and SS output, all others input */ 
	DDRB = (1<<BIT_MOSI)|(1<<BIT_CS)|(1<<BIT_SCK); 
	/* Enable SPI, Master, set clock rate fck/16 */ 
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
/************************************************************************/
void SPI_MasterTransmit(char cData) 
{ 
	/* Start transmission */ 
	SPDR = cData; 
	/* Wait for transmission complete */ 
	while(!(SPSR & (1<<SPIF))); 
	
} 
// Pętla główna
int main(void)
{
    spi_init();
    
   while (1) //Pętla główna
   {
			_delay_ms(1000); 
			PORTB &= ~(1<<BIT_CS); 
			_delay_ms(1000); 
			SPI_MasterTransmit('Y'); 
			_delay_ms(1000); 
			PORTB |= (1<<BIT_CS);
    }
}
I nic. Może ktoś widzi błąd w moim rozumowaniu. Czy to dlatego, że nie używam pinu /SS ? Zamiast niego używam pinu PB1.

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 19 paź 2013, 20:57

Programu w C ci nie napiszę, bo bardzo nie znam go na AVRy.
Ale sprawdź:
Poprawność ustawienia portów CPU.
Poprawność konfiguracji modułu SPI

z tego co zauważyłem w programie.
A. Chcesz wysyłać bajt danych, a nie ustawiasz przed tym, FSYNC (CS) w stan niski.
B. Pamietaj że FSYNC (CS) musisz zdjąć po wysłaniu dwóch bajtów, bo ten AD odbiera dane 16-bitowe.

adi19887
-
Posty: 52
Rejestracja: 22 mar 2010, 23:48
Lokalizacja: Poznań

Post autor: adi19887 » 20 paź 2013, 9:52

Dziękuje za odpowiedź. Odnoszę się teraz do 2 kodu wrzuconego do tego tematu.

Kod: Zaznacz cały

PORTB &= ~(1<<BIT_CS); 
Tutaj ustawiam stan niski na Fsync (na delaye nie zwracajcie uwagi chciałem zobaczyc na oscyloskopie czy cos sie dzieje dlatego takie opoźnienia). Rzeczywiście atmega ustawia i kasuje pin PB1 zgodnie z zapisem w kodzie programu (przełącza 0-1).
Do do danych to ma to przerobione. Tutaj podaje kod taki bo w ogóle mi SPI nie rusza. We właściwym kodzie mam procedure napisaną zgodnie z zaleceniami ze strony Analog Devices.
Czy gdzieś robię logiczny błąd ? W fuse bitach zmieniona jest wartość odpowiadająca za źrodlo taktowania. Wszystko robie w Mkavrcalculator.

ODPOWIEDZ